blob: 3fbacb297732167e036833bf6d16bb46b88631b9 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Roland McGrath48a035f2006-01-12 09:45:56 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000328 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000330 return 0;
331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000370 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000552#endif
553#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000554 case SYS_writev:
555 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
556 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
557 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000558#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 }
560}
561
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000562#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000563enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000564#else /* FREEBSD */
565enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
566
567struct subcall {
568 int call;
569 int nsubcalls;
570 int subcalls[5];
571};
572
Roland McGratha4d48532005-06-08 20:45:28 +0000573static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000574 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000575#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000576 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000577#else
578 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
579#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000580 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
581};
582#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000584#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585
Roland McGratha4d48532005-06-08 20:45:28 +0000586static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587decode_subcall(tcp, subcall, nsubcalls, style)
588struct tcb *tcp;
589int subcall;
590int nsubcalls;
591enum subcall_style style;
592{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000593 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000594 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000595 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 switch (style) {
598 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000599 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
600 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601 tcp->scno = subcall + tcp->u_arg[0];
602 if (sysent[tcp->scno].nargs != -1)
603 tcp->u_nargs = sysent[tcp->scno].nargs;
604 else
605 tcp->u_nargs--;
606 for (i = 0; i < tcp->u_nargs; i++)
607 tcp->u_arg[i] = tcp->u_arg[i + 1];
608 break;
609 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000610 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
611 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 tcp->scno = subcall + tcp->u_arg[0];
613 addr = tcp->u_arg[1];
614 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000615 if (size == sizeof(int)) {
616 unsigned int arg;
617 if (umove(tcp, addr, &arg) < 0)
618 arg = 0;
619 tcp->u_arg[i] = arg;
620 }
621 else if (size == sizeof(long)) {
622 unsigned long arg;
623 if (umove(tcp, addr, &arg) < 0)
624 arg = 0;
625 tcp->u_arg[i] = arg;
626 }
627 else
628 abort();
629 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
631 tcp->u_nargs = sysent[tcp->scno].nargs;
632 break;
633 case mask_style:
634 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 for (i = 0; mask; i++)
636 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000637 if (i >= nsubcalls)
638 return;
639 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tcp->scno = subcall + i;
641 if (sysent[tcp->scno].nargs != -1)
642 tcp->u_nargs = sysent[tcp->scno].nargs;
643 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000644 case door_style:
645 /*
646 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000647 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000648 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000649 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
650 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000651 tcp->scno = subcall + tcp->u_arg[5];
652 if (sysent[tcp->scno].nargs != -1)
653 tcp->u_nargs = sysent[tcp->scno].nargs;
654 else
655 tcp->u_nargs--;
656 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000657#ifdef FREEBSD
658 case table_style:
659 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
660 if (subcalls_table[i].call == tcp->scno) break;
661 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
662 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
663 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
664 for (i = 0; i < tcp->u_nargs; i++)
665 tcp->u_arg[i] = tcp->u_arg[i + 1];
666 }
667 break;
668#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669 }
670}
671#endif
672
673struct tcb *tcp_last = NULL;
674
675static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677{
678 /*
679 * We must always trace a few critical system calls in order to
680 * correctly support following forks in the presence of tracing
681 * qualifiers.
682 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
686 return 0;
687
688 func = sysent[tcp->scno].sys_func;
689
690 if (sys_exit == func)
691 return internal_exit(tcp);
692
693 if ( sys_fork == func
694#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
695 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000697#if UNIXWARE > 2
698 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000700 )
701 return internal_fork(tcp);
702
703#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
704 if (sys_clone == func)
705 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000706#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000708 if ( sys_execve == func
709#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
710 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000712#if UNIXWARE > 2
713 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000714#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000715 )
716 return internal_exec(tcp);
717
718 if ( sys_waitpid == func
719 || sys_wait4 == func
720#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
721 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000722#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000723#ifdef ALPHA
724 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000725#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000726 )
727 return internal_wait(tcp, 2);
728
729#if defined(LINUX) || defined(SVR4)
730 if (sys_waitid == func)
731 return internal_wait(tcp, 3);
732#endif
733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 return 0;
735}
736
Wichert Akkermanc7926982000-04-10 22:22:31 +0000737
738#ifdef LINUX
739#if defined (I386)
740 static long eax;
741#elif defined (IA64)
742 long r8, r10, psr;
743 long ia32 = 0;
744#elif defined (POWERPC)
745 static long result,flags;
746#elif defined (M68K)
747 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000748#elif defined(BFIN)
749 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000751 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000752#elif defined (ALPHA)
753 static long r0;
754 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000755#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000756 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000757 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000758#elif defined(LINUX_MIPSN32)
759 static long long a3;
760 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000761#elif defined(MIPS)
762 static long a3;
763 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000764#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000765 static long gpr2;
766 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000767 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000768#elif defined(HPPA)
769 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000770#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000771 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000772#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000773 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000774#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000775 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000776#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000777#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000778#ifdef FREEBSD
779 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000783get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784struct tcb *tcp;
785{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000787#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000789#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000792#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000793 if (tcp->flags & TCB_WAITEXECVE) {
794 /*
795 * When the execve system call completes successfully, the
796 * new process still has -ENOSYS (old style) or __NR_execve
797 * (new style) in gpr2. We cannot recover the scno again
798 * by disassembly, because the image that executed the
799 * syscall is gone now. Fortunately, we don't want it. We
800 * leave the flag set so that syscall_fixup can fake the
801 * result.
802 */
803 if (tcp->flags & TCB_INSYSCALL)
804 return 1;
805 /*
806 * This is the SIGTRAP after execve. We cannot try to read
807 * the system call here either.
808 */
809 tcp->flags &= ~TCB_WAITEXECVE;
810 return 0;
811 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000812
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000813 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000814 return -1;
815
816 if (syscall_mode != -ENOSYS) {
817 /*
818 * Since kernel version 2.5.44 the scno gets passed in gpr2.
819 */
820 scno = syscall_mode;
821 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 /*
823 * Old style of "passing" the scno via the SVC instruction.
824 */
825
826 long opcode, offset_reg, tmp;
827 void * svc_addr;
828 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
829 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
830 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
831 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000832
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000833 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000835 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000837 if (errno) {
838 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000839 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000840 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000841
842 /*
843 * We have to check if the SVC got executed directly or via an
844 * EXECUTE instruction. In case of EXECUTE it is necessary to do
845 * instruction decoding to derive the system call number.
846 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
847 * so that this doesn't work if a SVC opcode is part of an EXECUTE
848 * opcode. Since there is no way to find out the opcode size this
849 * is the best we can do...
850 */
851
852 if ((opcode & 0xff00) == 0x0a00) {
853 /* SVC opcode */
854 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000855 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 else {
857 /* SVC got executed by EXECUTE instruction */
858
859 /*
860 * Do instruction decoding of EXECUTE. If you really want to
861 * understand this, read the Principles of Operations.
862 */
863 svc_addr = (void *) (opcode & 0xfff);
864
865 tmp = 0;
866 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000867 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 return -1;
869 svc_addr += tmp;
870
871 tmp = 0;
872 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000873 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 return -1;
875 svc_addr += tmp;
876
877 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
878 if (errno)
879 return -1;
880#if defined(S390X)
881 scno >>= 48;
882#else
883 scno >>= 16;
884#endif
885 tmp = 0;
886 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000887 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000888 return -1;
889
890 scno = (scno | tmp) & 0xff;
891 }
892 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000893#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000894 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895 return -1;
896 if (!(tcp->flags & TCB_INSYSCALL)) {
897 /* Check if we return from execve. */
898 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
899 tcp->flags &= ~TCB_WAITEXECVE;
900 return 0;
901 }
902 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000903#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000904 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000905 return -1;
906 /* Check if we return from execve. */
907 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
908 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909#elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000910 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000912#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000913 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000914 return -1;
915
Roland McGrath761b5d72002-12-15 23:58:31 +0000916 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko8236f252009-01-02 18:10:08 +0000917 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000918 long val;
919
920 /* Check CS register value. On x86-64 linux it is:
921 * 0x33 for long mode (64 bit)
922 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000923 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 * to be cached.
925 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000926 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000928 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 case 0x23: currpers = 1; break;
930 case 0x33: currpers = 0; break;
931 default:
932 fprintf(stderr, "Unknown value CS=0x%02X while "
933 "detecting personality of process "
934 "PID=%d\n", (int)val, pid);
935 currpers = current_personality;
936 break;
937 }
938#if 0
939 /* This version analyzes the opcode of a syscall instruction.
940 * (int 0x80 on i386 vs. syscall on x86-64)
941 * It works, but is too complicated.
942 */
943 unsigned long val, rip, i;
944
Denys Vlasenko8236f252009-01-02 18:10:08 +0000945 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000947
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 errno = 0;
951
Denys Vlasenko8236f252009-01-02 18:10:08 +0000952 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 if (errno)
954 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000956 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000963 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
966 "PID=%d\n", (int)call, pid);
967 break;
968 }
969#endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 if (currpers != current_personality) {
971 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 pid, names[current_personality]);
975 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000977#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000978# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000979 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000980 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981 if (!(tcp->flags & TCB_INSYSCALL)) {
982 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000983 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 return -1;
985 } else {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000986 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 return -1;
988 }
Roland McGrathba954762003-03-05 06:29:06 +0000989 /* Check if we return from execve. */
990 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000991#if defined PTRACE_GETSIGINFO
992 siginfo_t si;
993
994 tcp->flags &= ~TCB_WAITEXECVE;
995 /* If SIGTRAP is masked, execve's magic SIGTRAP
996 * is not delivered. We end up here on a subsequent
997 * ptrace stop instead. Luckily, we can check
998 * for the type of this SIGTRAP. execve's magic one
999 * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
1000 * (I don't know why 5).
1001 */
1002 si.si_code = SI_USER;
1003 /* If PTRACE_GETSIGINFO fails, we assume it's
1004 * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
1005 * doesn't fail.
1006 */
1007 ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
1008 if (si.si_code == SI_USER)
1009 return 0;
1010#else
Roland McGrathba954762003-03-05 06:29:06 +00001011 tcp->flags &= ~TCB_WAITEXECVE;
1012 return 0;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001013#endif
Roland McGrathba954762003-03-05 06:29:06 +00001014 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001015 } else {
1016 /* syscall in progress */
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001017 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001018 return -1;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001019 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001020 return -1;
1021 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 /*
1024 * Read complete register set in one go.
1025 */
1026 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1027 return -1;
1028
1029 /*
1030 * We only need to grab the syscall number on syscall entry.
1031 */
1032 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001033 if (!(tcp->flags & TCB_INSYSCALL)) {
1034 /* Check if we return from execve. */
1035 if (tcp->flags & TCB_WAITEXECVE) {
1036 tcp->flags &= ~TCB_WAITEXECVE;
1037 return 0;
1038 }
1039 }
1040
Roland McGrath0f87c492003-06-03 23:29:04 +00001041 /*
1042 * Note: we only deal with only 32-bit CPUs here.
1043 */
1044 if (regs.ARM_cpsr & 0x20) {
1045 /*
1046 * Get the Thumb-mode system call number
1047 */
1048 scno = regs.ARM_r7;
1049 } else {
1050 /*
1051 * Get the ARM-mode system call number
1052 */
1053 errno = 0;
1054 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1055 if (errno)
1056 return -1;
1057
1058 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1059 tcp->flags &= ~TCB_WAITEXECVE;
1060 return 0;
1061 }
1062
Roland McGrathf691bd22006-04-25 07:34:41 +00001063 /* Handle the EABI syscall convention. We do not
1064 bother converting structures between the two
1065 ABIs, but basic functionality should work even
1066 if strace and the traced program have different
1067 ABIs. */
1068 if (scno == 0xef000000) {
1069 scno = regs.ARM_r7;
1070 } else {
1071 if ((scno & 0x0ff00000) != 0x0f900000) {
1072 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1073 scno);
1074 return -1;
1075 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001076
Roland McGrathf691bd22006-04-25 07:34:41 +00001077 /*
1078 * Fixup the syscall number
1079 */
1080 scno &= 0x000fffff;
1081 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001082 }
Roland McGrath56703312008-05-20 01:35:55 +00001083 if (scno & 0x0f0000) {
1084 /*
1085 * Handle ARM specific syscall
1086 */
1087 set_personality(1);
1088 scno &= 0x0000ffff;
1089 } else
1090 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001091
1092 if (tcp->flags & TCB_INSYSCALL) {
1093 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1094 tcp->flags &= ~TCB_INSYSCALL;
1095 }
1096 } else {
1097 if (!(tcp->flags & TCB_INSYSCALL)) {
1098 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1099 tcp->flags |= TCB_INSYSCALL;
1100 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 }
1102#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001103 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001105#elif defined (LINUX_MIPSN32)
1106 unsigned long long regs[38];
1107
1108 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1109 return -1;
1110 a3 = regs[REG_A3];
1111 r2 = regs[REG_V0];
1112
1113 if(!(tcp->flags & TCB_INSYSCALL)) {
1114 scno = r2;
1115
1116 /* Check if we return from execve. */
1117 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1118 tcp->flags &= ~TCB_WAITEXECVE;
1119 return 0;
1120 }
1121
1122 if (scno < 0 || scno > nsyscalls) {
1123 if(a3 == 0 || a3 == -1) {
1124 if(debug)
1125 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1126 return 0;
1127 }
1128 }
1129 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130#elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001133 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001135 return -1;
1136
Roland McGrath542c2c62008-05-20 01:11:56 +00001137 /* Check if we return from execve. */
1138 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1139 tcp->flags &= ~TCB_WAITEXECVE;
1140 return 0;
1141 }
1142
Wichert Akkermanf90da011999-10-31 21:15:38 +00001143 if (scno < 0 || scno > nsyscalls) {
1144 if(a3 == 0 || a3 == -1) {
1145 if(debug)
1146 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1147 return 0;
1148 }
1149 }
1150 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001152 return -1;
1153 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154#elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 return -1;
1157
1158 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001159 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 return -1;
1161
1162 /* Check if we return from execve. */
1163 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1164 tcp->flags &= ~TCB_WAITEXECVE;
1165 return 0;
1166 }
1167
1168 /*
1169 * Do some sanity checks to figure out if it's
1170 * really a syscall entry
1171 */
1172 if (scno < 0 || scno > nsyscalls) {
1173 if (a3 == 0 || a3 == -1) {
1174 if (debug)
1175 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1176 return 0;
1177 }
1178 }
1179 }
1180 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001181 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 return -1;
1183 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001184#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 /* Everything we need is in the current register set. */
1186 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1187 return -1;
1188
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001189 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 if (!(tcp->flags & TCB_INSYSCALL)) {
1191 /* Retrieve the syscall trap instruction. */
1192 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001193 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001194#if defined(SPARC64)
1195 trap >>= 32;
1196#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 if (errno)
1198 return -1;
1199
1200 /* Disassemble the trap to see what personality to use. */
1201 switch (trap) {
1202 case 0x91d02010:
1203 /* Linux/SPARC syscall trap. */
1204 set_personality(0);
1205 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001206 case 0x91d0206d:
1207 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001208 set_personality(2);
1209 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 case 0x91d02000:
1211 /* SunOS syscall trap. (pers 1) */
1212 fprintf(stderr,"syscall: SunOS no support\n");
1213 return -1;
1214 case 0x91d02008:
1215 /* Solaris 2.x syscall trap. (per 2) */
1216 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001217 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 case 0x91d02009:
1219 /* NetBSD/FreeBSD syscall trap. */
1220 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1221 return -1;
1222 case 0x91d02027:
1223 /* Solaris 2.x gettimeofday */
1224 set_personality(1);
1225 break;
1226 default:
1227 /* Unknown syscall trap. */
1228 if(tcp->flags & TCB_WAITEXECVE) {
1229 tcp->flags &= ~TCB_WAITEXECVE;
1230 return 0;
1231 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001232#if defined (SPARC64)
1233 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1234#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001235 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001236#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 return -1;
1238 }
1239
1240 /* Extract the system call number from the registers. */
1241 if (trap == 0x91d02027)
1242 scno = 156;
1243 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001244 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001246 scno = regs.r_o0;
1247 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 }
1249 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001250#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001251 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001252 return -1;
1253 if (!(tcp->flags & TCB_INSYSCALL)) {
1254 /* Check if we return from execve. */
1255 if ((tcp->flags & TCB_WAITEXECVE)) {
1256 tcp->flags &= ~TCB_WAITEXECVE;
1257 return 0;
1258 }
1259 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001260#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001261 /*
1262 * In the new syscall ABI, the system call number is in R3.
1263 */
1264 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1265 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001266
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001267 if (scno < 0) {
1268 /* Odd as it may seem, a glibc bug has been known to cause
1269 glibc to issue bogus negative syscall numbers. So for
1270 our purposes, make strace print what it *should* have been */
1271 long correct_scno = (scno & 0xff);
1272 if (debug)
1273 fprintf(stderr,
1274 "Detected glibc bug: bogus system call"
1275 " number = %ld, correcting to %ld\n",
1276 scno,
1277 correct_scno);
1278 scno = correct_scno;
1279 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001280
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001281 if (!(tcp->flags & TCB_INSYSCALL)) {
1282 /* Check if we return from execve. */
1283 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1284 tcp->flags &= ~TCB_WAITEXECVE;
1285 return 0;
1286 }
1287 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001288#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001289 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001291 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001292
1293 if (!(tcp->flags & TCB_INSYSCALL)) {
1294 /* Check if we return from execve. */
1295 if (tcp->flags & TCB_WAITEXECVE) {
1296 tcp->flags &= ~TCB_WAITEXECVE;
1297 return 0;
1298 }
1299 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001300#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301#endif /* LINUX */
1302#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001303 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001305#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001306 /* new syscall ABI returns result in R0 */
1307 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1308 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001309#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001310 /* ABI defines result returned in r9 */
1311 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1312 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001313
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001315#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001317 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001320 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#else /* FREEBSD */
1322 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001323 perror("pread");
1324 return -1;
1325 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326 switch (regs.r_eax) {
1327 case SYS_syscall:
1328 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001329 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1330 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001332 scno = regs.r_eax;
1333 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001334 }
1335#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001337#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001338 if (!(tcp->flags & TCB_INSYSCALL))
1339 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001340 return 1;
1341}
1342
Pavel Machek4dc3b142000-02-01 17:58:41 +00001343
Roland McGrath17352792005-06-07 23:21:26 +00001344long
1345known_scno(tcp)
1346struct tcb *tcp;
1347{
1348 long scno = tcp->scno;
1349 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1350 scno = sysent[scno].native_scno;
1351 else
1352 scno += NR_SYSCALL_BASE;
1353 return scno;
1354}
1355
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001356/* Called in trace_syscall() at each syscall entry and exit.
1357 * Returns:
1358 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1359 * 1: ok, continue in trace_syscall().
1360 * other: error, trace_syscall() should print error indicator
1361 * ("????" etc) and bail out.
1362 */
Roland McGratha4d48532005-06-08 20:45:28 +00001363static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001364syscall_fixup(tcp)
1365struct tcb *tcp;
1366{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001367#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001368 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001369
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001371 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001372 if (
1373 scno == SYS_fork
1374#ifdef SYS_vfork
1375 || scno == SYS_vfork
1376#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001377#ifdef SYS_fork1
1378 || scno == SYS_fork1
1379#endif /* SYS_fork1 */
1380#ifdef SYS_forkall
1381 || scno == SYS_forkall
1382#endif /* SYS_forkall */
1383#ifdef SYS_rfork1
1384 || scno == SYS_rfork1
1385#endif /* SYS_fork1 */
1386#ifdef SYS_rforkall
1387 || scno == SYS_rforkall
1388#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389 ) {
1390 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001391 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001393 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001394 }
1395 else {
1396 fprintf(stderr, "syscall: missing entry\n");
1397 tcp->flags |= TCB_INSYSCALL;
1398 }
1399 }
1400 }
1401 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001402 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001403 fprintf(stderr, "syscall: missing exit\n");
1404 tcp->flags &= ~TCB_INSYSCALL;
1405 }
1406 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001407#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408#ifdef SUNOS4
1409 if (!(tcp->flags & TCB_INSYSCALL)) {
1410 if (scno == 0) {
1411 fprintf(stderr, "syscall: missing entry\n");
1412 tcp->flags |= TCB_INSYSCALL;
1413 }
1414 }
1415 else {
1416 if (scno != 0) {
1417 if (debug) {
1418 /*
1419 * This happens when a signal handler
1420 * for a signal which interrupted a
1421 * a system call makes another system call.
1422 */
1423 fprintf(stderr, "syscall: missing exit\n");
1424 }
1425 tcp->flags &= ~TCB_INSYSCALL;
1426 }
1427 }
1428#endif /* SUNOS4 */
1429#ifdef LINUX
1430#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001431 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432 return -1;
1433 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1434 if (debug)
1435 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1436 return 0;
1437 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001438#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001439 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001440 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001441 if (current_personality == 1)
1442 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001443 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1444 if (debug)
1445 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1446 return 0;
1447 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001448#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001449 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001450 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001451 if (syscall_mode != -ENOSYS)
1452 syscall_mode = tcp->scno;
1453 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001454 if (debug)
1455 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1456 return 0;
1457 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001458 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1459 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1460 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1461 /*
1462 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1463 * flag set for the post-execve SIGTRAP to see and reset.
1464 */
1465 gpr2 = 0;
1466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467#elif defined (POWERPC)
1468# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001469 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001471 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472 return -1;
1473 if (flags & SO_MASK)
1474 result = -result;
1475#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001476 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001477 return -1;
1478 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1479 if (debug)
1480 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1481 return 0;
1482 }
1483#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001484 /*
1485 * Nothing required
1486 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001487#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001488 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001489 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001490#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001491 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001492 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001493#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001494 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001495 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001496 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001497 return -1;
1498 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1499 if (debug)
1500 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1501 return 0;
1502 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001503#endif
1504#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001505 return 1;
1506}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507
Roland McGrathc1e45922008-05-27 23:18:29 +00001508#ifdef LINUX
1509/*
1510 * Check the syscall return value register value for whether it is
1511 * a negated errno code indicating an error, or a success return value.
1512 */
1513static inline int
1514is_negated_errno(unsigned long int val)
1515{
1516 unsigned long int max = -(long int) nerrnos;
1517 if (personality_wordsize[current_personality] < sizeof(val)) {
1518 val = (unsigned int) val;
1519 max = (unsigned int) max;
1520 }
1521 return val > max;
1522}
1523#endif
1524
Roland McGratha4d48532005-06-08 20:45:28 +00001525static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001526get_error(tcp)
1527struct tcb *tcp;
1528{
1529 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001531#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001532 if (is_negated_errno(gpr2)) {
1533 tcp->u_rval = -1;
1534 u_error = -gpr2;
1535 }
1536 else {
1537 tcp->u_rval = gpr2;
1538 u_error = 0;
1539 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001540#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 if (is_negated_errno(eax)) {
1543 tcp->u_rval = -1;
1544 u_error = -eax;
1545 }
1546 else {
1547 tcp->u_rval = eax;
1548 u_error = 0;
1549 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001551#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001552 if (is_negated_errno(rax)) {
1553 tcp->u_rval = -1;
1554 u_error = -rax;
1555 }
1556 else {
1557 tcp->u_rval = rax;
1558 u_error = 0;
1559 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001560#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001561#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001562 if (ia32) {
1563 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001564
Roland McGrathc1e45922008-05-27 23:18:29 +00001565 err = (int)r8;
1566 if (is_negated_errno(err)) {
1567 tcp->u_rval = -1;
1568 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001569 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001570 else {
1571 tcp->u_rval = err;
1572 u_error = 0;
1573 }
1574 } else {
1575 if (r10) {
1576 tcp->u_rval = -1;
1577 u_error = r8;
1578 } else {
1579 tcp->u_rval = r8;
1580 u_error = 0;
1581 }
1582 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001583#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001584#ifdef MIPS
1585 if (a3) {
1586 tcp->u_rval = -1;
1587 u_error = r2;
1588 } else {
1589 tcp->u_rval = r2;
1590 u_error = 0;
1591 }
1592#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001594 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595 tcp->u_rval = -1;
1596 u_error = -result;
1597 }
1598 else {
1599 tcp->u_rval = result;
1600 u_error = 0;
1601 }
1602#else /* !POWERPC */
1603#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001604 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 tcp->u_rval = -1;
1606 u_error = -d0;
1607 }
1608 else {
1609 tcp->u_rval = d0;
1610 u_error = 0;
1611 }
1612#else /* !M68K */
1613#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001614 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001616 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 }
1618 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001619 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 u_error = 0;
1621 }
1622#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001623#ifdef BFIN
1624 if (is_negated_errno(r0)) {
1625 tcp->u_rval = -1;
1626 u_error = -r0;
1627 } else {
1628 tcp->u_rval = r0;
1629 u_error = 0;
1630 }
1631#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632#ifdef ALPHA
1633 if (a3) {
1634 tcp->u_rval = -1;
1635 u_error = r0;
1636 }
1637 else {
1638 tcp->u_rval = r0;
1639 u_error = 0;
1640 }
1641#else /* !ALPHA */
1642#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001643 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001645 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 }
1647 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001648 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 u_error = 0;
1650 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001651#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001652#ifdef SPARC64
1653 if (regs.r_tstate & 0x1100000000UL) {
1654 tcp->u_rval = -1;
1655 u_error = regs.r_o0;
1656 }
1657 else {
1658 tcp->u_rval = regs.r_o0;
1659 u_error = 0;
1660 }
1661#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001662#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001663 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001664 tcp->u_rval = -1;
1665 u_error = -r28;
1666 }
1667 else {
1668 tcp->u_rval = r28;
1669 u_error = 0;
1670 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001671#else
1672#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001673 /* interpret R0 as return value or error number */
1674 if (is_negated_errno(r0)) {
1675 tcp->u_rval = -1;
1676 u_error = -r0;
1677 }
1678 else {
1679 tcp->u_rval = r0;
1680 u_error = 0;
1681 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001682#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001683#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001684 /* interpret result as return value or error number */
1685 if (is_negated_errno(r9)) {
1686 tcp->u_rval = -1;
1687 u_error = -r9;
1688 }
1689 else {
1690 tcp->u_rval = r9;
1691 u_error = 0;
1692 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001693#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001694#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001695#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001697#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001699#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700#endif /* ARM */
1701#endif /* M68K */
1702#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001703#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001704#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001705#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001707#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708#endif /* LINUX */
1709#ifdef SUNOS4
1710 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001711 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 return -1;
1713 u_error >>= 24; /* u_error is a char */
1714
1715 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001716 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717 return -1;
1718#endif /* SUNOS4 */
1719#ifdef SVR4
1720#ifdef SPARC
1721 /* Judicious guessing goes a long way. */
1722 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1723 tcp->u_rval = -1;
1724 u_error = tcp->status.pr_reg[R_O0];
1725 }
1726 else {
1727 tcp->u_rval = tcp->status.pr_reg[R_O0];
1728 u_error = 0;
1729 }
1730#endif /* SPARC */
1731#ifdef I386
1732 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001733 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001735 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 }
1737 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001738 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001739#ifdef HAVE_LONG_LONG
1740 tcp->u_lrval =
1741 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1742 tcp->status.PR_REG[EAX];
1743#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 u_error = 0;
1745 }
1746#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001747#ifdef X86_64
1748 /* Wanna know how to kill an hour single-stepping? */
1749 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1750 tcp->u_rval = -1;
1751 u_error = tcp->status.PR_REG[RAX];
1752 }
1753 else {
1754 tcp->u_rval = tcp->status.PR_REG[RAX];
1755 u_error = 0;
1756 }
1757#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758#ifdef MIPS
1759 if (tcp->status.pr_reg[CTX_A3]) {
1760 tcp->u_rval = -1;
1761 u_error = tcp->status.pr_reg[CTX_V0];
1762 }
1763 else {
1764 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1765 u_error = 0;
1766 }
1767#endif /* MIPS */
1768#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001769#ifdef FREEBSD
1770 if (regs.r_eflags & PSL_C) {
1771 tcp->u_rval = -1;
1772 u_error = regs.r_eax;
1773 } else {
1774 tcp->u_rval = regs.r_eax;
1775 tcp->u_lrval =
1776 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1777 u_error = 0;
1778 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001779#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001780 tcp->u_error = u_error;
1781 return 1;
1782}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784int
1785force_result(tcp, error, rval)
1786 struct tcb *tcp;
1787 int error;
1788 long rval;
1789{
1790#ifdef LINUX
1791#if defined(S390) || defined(S390X)
1792 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1794 return -1;
1795#else /* !S390 && !S390X */
1796#ifdef I386
1797 eax = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1799 return -1;
1800#else /* !I386 */
1801#ifdef X86_64
1802 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001804 return -1;
1805#else
1806#ifdef IA64
1807 if (ia32) {
1808 r8 = error ? -error : rval;
1809 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1810 return -1;
1811 }
1812 else {
1813 if (error) {
1814 r8 = error;
1815 r10 = -1;
1816 }
1817 else {
1818 r8 = rval;
1819 r10 = 0;
1820 }
1821 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1822 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1823 return -1;
1824 }
1825#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001826#ifdef BFIN
1827 r0 = error ? -error : rval;
1828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1829 return -1;
1830#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001831#ifdef MIPS
1832 if (error) {
1833 r2 = error;
1834 a3 = -1;
1835 }
1836 else {
1837 r2 = rval;
1838 a3 = 0;
1839 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001840 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1842 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1843 return -1;
1844#else
1845#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001846 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 return -1;
1848 if (error) {
1849 flags |= SO_MASK;
1850 result = error;
1851 }
1852 else {
1853 flags &= ~SO_MASK;
1854 result = rval;
1855 }
Roland McGratheb285352003-01-14 09:59:00 +00001856 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1857 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001858 return -1;
1859#else /* !POWERPC */
1860#ifdef M68K
1861 d0 = error ? -error : rval;
1862 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1863 return -1;
1864#else /* !M68K */
1865#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001866 regs.ARM_r0 = error ? -error : rval;
1867 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001868 return -1;
1869#else /* !ARM */
1870#ifdef ALPHA
1871 if (error) {
1872 a3 = -1;
1873 r0 = error;
1874 }
1875 else {
1876 a3 = 0;
1877 r0 = rval;
1878 }
1879 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1880 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1881 return -1;
1882#else /* !ALPHA */
1883#ifdef SPARC
1884 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1885 return -1;
1886 if (error) {
1887 regs.r_psr |= PSR_C;
1888 regs.r_o0 = error;
1889 }
1890 else {
1891 regs.r_psr &= ~PSR_C;
1892 regs.r_o0 = rval;
1893 }
1894 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1895 return -1;
1896#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001897#ifdef SPARC64
1898 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1899 return -1;
1900 if (error) {
1901 regs.r_tstate |= 0x1100000000UL;
1902 regs.r_o0 = error;
1903 }
1904 else {
1905 regs.r_tstate &= ~0x1100000000UL;
1906 regs.r_o0 = rval;
1907 }
1908 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1909 return -1;
1910#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001911#ifdef HPPA
1912 r28 = error ? -error : rval;
1913 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1914 return -1;
1915#else
1916#ifdef SH
1917 r0 = error ? -error : rval;
1918 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1919 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001920#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001921#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001922 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001923 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1924 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001925#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001926#endif /* SH */
1927#endif /* HPPA */
1928#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001929#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930#endif /* ALPHA */
1931#endif /* ARM */
1932#endif /* M68K */
1933#endif /* POWERPC */
1934#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001935#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001936#endif /* IA64 */
1937#endif /* X86_64 */
1938#endif /* I386 */
1939#endif /* S390 || S390X */
1940#endif /* LINUX */
1941#ifdef SUNOS4
1942 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1943 error << 24) < 0 ||
1944 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1945 return -1;
1946#endif /* SUNOS4 */
1947#ifdef SVR4
1948 /* XXX no clue */
1949 return -1;
1950#endif /* SVR4 */
1951#ifdef FREEBSD
1952 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001953 perror("pread");
1954 return -1;
1955 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001956 if (error) {
1957 regs.r_eflags |= PSL_C;
1958 regs.r_eax = error;
1959 }
1960 else {
1961 regs.r_eflags &= ~PSL_C;
1962 regs.r_eax = rval;
1963 }
1964 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001965 perror("pwrite");
1966 return -1;
1967 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001968#endif /* FREEBSD */
1969
1970 /* All branches reach here on success (only). */
1971 tcp->u_error = error;
1972 tcp->u_rval = rval;
1973 return 0;
1974}
1975
Roland McGratha4d48532005-06-08 20:45:28 +00001976static int
1977syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001978struct tcb *tcp;
1979{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001981#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001982 {
1983 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001984 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1985 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001986 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001987 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001988 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001989 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001990 return -1;
1991 }
1992 }
1993#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994 {
1995 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001996 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1997 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001998 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001999 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002001 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2002 * for scno somewhere above here!
2003 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002004 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002005 return -1;
2006 }
2007 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002008#elif defined (IA64)
2009 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002010 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002011 unsigned long *out0, cfm, sof, sol, i;
2012 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002013 /* be backwards compatible with kernel < 2.4.4... */
2014# ifndef PT_RBS_END
2015# define PT_RBS_END PT_AR_BSP
2016# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002017
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002018 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002019 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002020 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002021 return -1;
2022
2023 sof = (cfm >> 0) & 0x7f;
2024 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002025 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002026
2027 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2028 && sysent[tcp->scno].nargs != -1)
2029 tcp->u_nargs = sysent[tcp->scno].nargs;
2030 else
2031 tcp->u_nargs = MAX_ARGS;
2032 for (i = 0; i < tcp->u_nargs; ++i) {
2033 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2034 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2035 return -1;
2036 }
2037 } else {
2038 int i;
2039
2040 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002041 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002042 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002043 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002044 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002045 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002046 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002047 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002048 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002049 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002050 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002051 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002052 return -1;
2053
2054 for (i = 0; i < 6; ++i)
2055 /* truncate away IVE sign-extension */
2056 tcp->u_arg[i] &= 0xffffffff;
2057
2058 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2059 && sysent[tcp->scno].nargs != -1)
2060 tcp->u_nargs = sysent[tcp->scno].nargs;
2061 else
2062 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002063 }
2064 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002065#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2066 /* N32 and N64 both use up to six registers. */
2067 {
2068 unsigned long long regs[38];
2069 int i, nargs;
2070
2071 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2072 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002073 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002074 nargs = tcp->u_nargs = MAX_ARGS;
2075
2076 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2077 return -1;
2078
2079 for(i = 0; i < nargs; i++) {
2080 tcp->u_arg[i] = regs[REG_A0 + i];
2081# if defined (LINUX_MIPSN32)
2082 tcp->ext_arg[i] = regs[REG_A0 + i];
2083# endif
2084 }
2085 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002086#elif defined (MIPS)
2087 {
2088 long sp;
2089 int i, nargs;
2090
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002091 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2092 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002093 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002094 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002095 if(nargs > 4) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002096 if(upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002097 return -1;
2098 for(i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002099 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002100 return -1;
2101 }
2102 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2103 (char *)(tcp->u_arg + 4));
2104 } else {
2105 for(i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002106 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002107 return -1;
2108 }
2109 }
2110 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002112#ifndef PT_ORIG_R3
2113#define PT_ORIG_R3 34
2114#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 {
2116 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002117 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2118 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002119 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002120 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002122 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002123 (sizeof(unsigned long)*PT_ORIG_R3) :
2124 ((i+PT_R3)*sizeof(unsigned long)),
2125 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002126 return -1;
2127 }
2128 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002129#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002131 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002132
2133 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2134 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002135 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002136 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002138 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002140#elif defined (HPPA)
2141 {
2142 int i;
2143
2144 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2145 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002146 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002147 tcp->u_nargs = MAX_ARGS;
2148 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002149 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002150 return -1;
2151 }
2152 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002153#elif defined(ARM)
2154 {
2155 int i;
2156
2157 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2158 tcp->u_nargs = sysent[tcp->scno].nargs;
2159 else
2160 tcp->u_nargs = MAX_ARGS;
2161 for (i = 0; i < tcp->u_nargs; i++)
2162 tcp->u_arg[i] = regs.uregs[i];
2163 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002164#elif defined(BFIN)
2165 {
2166 int i;
2167 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2168
2169 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2170 tcp->u_nargs = sysent[tcp->scno].nargs;
2171 else
2172 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2173
2174 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002175 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002176 return -1;
2177 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002178#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002179 {
2180 int i;
2181 static int syscall_regs[] = {
2182 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2183 REG_REG0, REG_REG0+1, REG_REG0+2
2184 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002185
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002186 tcp->u_nargs = sysent[tcp->scno].nargs;
2187 for (i = 0; i < tcp->u_nargs; i++) {
2188 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2189 return -1;
2190 }
2191 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002192#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002193 {
2194 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002195 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002196 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2197
2198 /*
2199 * TODO: should also check that the number of arguments encoded
2200 * in the trap number matches the number strace expects.
2201 */
2202 /*
2203 assert(sysent[tcp->scno].nargs <
2204 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2205 */
2206
2207 tcp->u_nargs = sysent[tcp->scno].nargs;
2208 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002209 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002210 return -1;
2211 }
2212 }
2213
Michal Ludvig0e035502002-09-23 15:41:01 +00002214#elif defined(X86_64)
2215 {
2216 int i;
2217 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2218 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002219 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002220 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002221
Michal Ludvig0e035502002-09-23 15:41:01 +00002222 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2223 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002224 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002225 tcp->u_nargs = MAX_ARGS;
2226 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002227 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002228 return -1;
2229 }
2230 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002231#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002232 {
2233 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2235 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002236 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002237 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002239 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002240 return -1;
2241 }
2242 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002243#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002244#endif /* LINUX */
2245#ifdef SUNOS4
2246 {
2247 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002248 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2249 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002250 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002251 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002252 for (i = 0; i < tcp->u_nargs; i++) {
2253 struct user *u;
2254
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002255 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002256 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2257 return -1;
2258 }
2259 }
2260#endif /* SUNOS4 */
2261#ifdef SVR4
2262#ifdef MIPS
2263 /*
2264 * SGI is broken: even though it has pr_sysarg, it doesn't
2265 * set them on system call entry. Get a clue.
2266 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = tcp->status.pr_nsysarg;
2271 if (tcp->u_nargs > 4) {
2272 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2273 4*sizeof(tcp->u_arg[0]));
2274 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2275 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2276 }
2277 else {
2278 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2279 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2280 }
John Hughes25299712001-03-06 10:10:06 +00002281#elif UNIXWARE >= 2
2282 /*
2283 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2284 */
2285 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2286 tcp->u_nargs = sysent[tcp->scno].nargs;
2287 else
2288 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2289 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2290 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2291#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002292 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 tcp->u_nargs = sysent[tcp->scno].nargs;
2294 else
2295 tcp->u_nargs = tcp->status.pr_nsysarg;
2296 {
2297 int i;
2298 for (i = 0; i < tcp->u_nargs; i++)
2299 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2300 }
John Hughes25299712001-03-06 10:10:06 +00002301#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002302 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002303 tcp->u_nargs = sysent[tcp->scno].nargs;
2304 else
2305 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002306 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002308#else
2309 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002311#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002312#ifdef FREEBSD
2313 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2314 sysent[tcp->scno].nargs > tcp->status.val)
2315 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002316 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002317 tcp->u_nargs = tcp->status.val;
2318 if (tcp->u_nargs < 0)
2319 tcp->u_nargs = 0;
2320 if (tcp->u_nargs > MAX_ARGS)
2321 tcp->u_nargs = MAX_ARGS;
2322 switch(regs.r_eax) {
2323 case SYS___syscall:
2324 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2325 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002326 break;
2327 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002328 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2329 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002330 break;
2331 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002332 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2333 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002334 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002335 }
2336#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002337 return 1;
2338}
2339
2340int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002341trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002342{
2343 int sys_res;
2344 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002345 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002346
2347 if (tcp->flags & TCB_INSYSCALL) {
2348 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002349
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002350 /* Measure the exit time as early as possible to avoid errors. */
2351 if (dtime)
2352 gettimeofday(&tv, NULL);
2353
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002354 /* BTW, why we don't just memorize syscall no. on entry
2355 * in tcp->something?
2356 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002357 scno_good = res = get_scno(tcp);
2358 if (res == 0)
2359 return res;
2360 if (res == 1)
2361 res = syscall_fixup(tcp);
2362 if (res == 0)
2363 return res;
2364 if (res == 1)
2365 res = get_error(tcp);
2366 if (res == 0)
2367 return res;
2368 if (res == 1)
2369 internal_syscall(tcp);
2370
2371 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002372 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002373 tcp->flags &= ~TCB_INSYSCALL;
2374 return 0;
2375 }
2376
2377 if (tcp->flags & TCB_REPRINT) {
2378 printleader(tcp);
2379 tprintf("<... ");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002380 if (scno_good != 1)
2381 tprintf("????");
2382 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002383 tprintf("syscall_%lu", tcp->scno);
2384 else
2385 tprintf("%s", sysent[tcp->scno].sys_name);
2386 tprintf(" resumed> ");
2387 }
2388
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002389 if (cflag)
2390 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002391
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002392 if (res != 1) {
2393 tprintf(") ");
2394 tabto(acolumn);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002395 tprintf("= ? <unavailable>");
2396 printtrailer();
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002397 tcp->flags &= ~TCB_INSYSCALL;
2398 return res;
2399 }
2400
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002401 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002402 || (qual_flags[tcp->scno] & QUAL_RAW))
2403 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002404 else {
2405 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002406 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002407 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002408 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002409 u_error = tcp->u_error;
2410 tprintf(") ");
2411 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002412 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2413 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002414 if (u_error)
2415 tprintf("= -1 (errno %ld)", u_error);
2416 else
2417 tprintf("= %#lx", tcp->u_rval);
2418 }
2419 else if (!(sys_res & RVAL_NONE) && u_error) {
2420 switch (u_error) {
2421#ifdef LINUX
2422 case ERESTARTSYS:
2423 tprintf("= ? ERESTARTSYS (To be restarted)");
2424 break;
2425 case ERESTARTNOINTR:
2426 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2427 break;
2428 case ERESTARTNOHAND:
2429 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2430 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002431 case ERESTART_RESTARTBLOCK:
2432 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2433 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002434#endif /* LINUX */
2435 default:
2436 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002437 if (u_error < 0)
2438 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002439 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002440 tprintf("%s (%s)", errnoent[u_error],
2441 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002442 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002443 tprintf("ERRNO_%ld (%s)", u_error,
2444 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002445 break;
2446 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002447 if ((sys_res & RVAL_STR) && tcp->auxstr)
2448 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002449 }
2450 else {
2451 if (sys_res & RVAL_NONE)
2452 tprintf("= ?");
2453 else {
2454 switch (sys_res & RVAL_MASK) {
2455 case RVAL_HEX:
2456 tprintf("= %#lx", tcp->u_rval);
2457 break;
2458 case RVAL_OCTAL:
2459 tprintf("= %#lo", tcp->u_rval);
2460 break;
2461 case RVAL_UDECIMAL:
2462 tprintf("= %lu", tcp->u_rval);
2463 break;
2464 case RVAL_DECIMAL:
2465 tprintf("= %ld", tcp->u_rval);
2466 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002467#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002468 case RVAL_LHEX:
2469 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002470 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002471 case RVAL_LOCTAL:
2472 tprintf("= %#llo", tcp->u_lrval);
2473 break;
2474 case RVAL_LUDECIMAL:
2475 tprintf("= %llu", tcp->u_lrval);
2476 break;
2477 case RVAL_LDECIMAL:
2478 tprintf("= %lld", tcp->u_lrval);
2479 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002480#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002481 default:
2482 fprintf(stderr,
2483 "invalid rval format\n");
2484 break;
2485 }
2486 }
2487 if ((sys_res & RVAL_STR) && tcp->auxstr)
2488 tprintf(" (%s)", tcp->auxstr);
2489 }
2490 if (dtime) {
2491 tv_sub(&tv, &tv, &tcp->etime);
2492 tprintf(" <%ld.%06ld>",
2493 (long) tv.tv_sec, (long) tv.tv_usec);
2494 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002495 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002496
2497 dumpio(tcp);
2498 if (fflush(tcp->outf) == EOF)
2499 return -1;
2500 tcp->flags &= ~TCB_INSYSCALL;
2501 return 0;
2502 }
2503
2504 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002505 scno_good = res = get_scno(tcp);
2506 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002507 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002508 if (res == 1)
2509 res = syscall_fixup(tcp);
2510 if (res == 0)
2511 return res;
2512 if (res == 1)
2513 res = syscall_enter(tcp);
2514 if (res == 0)
2515 return res;
2516
2517 if (res != 1) {
2518 printleader(tcp);
2519 tcp->flags &= ~TCB_REPRINT;
2520 tcp_last = tcp;
2521 if (scno_good != 1)
2522 tprintf("????" /* anti-trigraph gap */ "(");
2523 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2524 tprintf("syscall_%lu(", tcp->scno);
2525 else
2526 tprintf("%s(", sysent[tcp->scno].sys_name);
2527 /*
2528 * " <unavailable>" will be added later by the code which
2529 * detects ptrace errors.
2530 */
2531 tcp->flags |= TCB_INSYSCALL;
2532 return res;
2533 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002534
Roland McGrath17352792005-06-07 23:21:26 +00002535 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002536#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 case SYS_socketcall:
2538 decode_subcall(tcp, SYS_socket_subcall,
2539 SYS_socket_nsubcalls, deref_style);
2540 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002541#endif
2542#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543 case SYS_ipc:
2544 decode_subcall(tcp, SYS_ipc_subcall,
2545 SYS_ipc_nsubcalls, shift_style);
2546 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002547#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002548#ifdef SVR4
2549#ifdef SYS_pgrpsys_subcall
2550 case SYS_pgrpsys:
2551 decode_subcall(tcp, SYS_pgrpsys_subcall,
2552 SYS_pgrpsys_nsubcalls, shift_style);
2553 break;
2554#endif /* SYS_pgrpsys_subcall */
2555#ifdef SYS_sigcall_subcall
2556 case SYS_sigcall:
2557 decode_subcall(tcp, SYS_sigcall_subcall,
2558 SYS_sigcall_nsubcalls, mask_style);
2559 break;
2560#endif /* SYS_sigcall_subcall */
2561 case SYS_msgsys:
2562 decode_subcall(tcp, SYS_msgsys_subcall,
2563 SYS_msgsys_nsubcalls, shift_style);
2564 break;
2565 case SYS_shmsys:
2566 decode_subcall(tcp, SYS_shmsys_subcall,
2567 SYS_shmsys_nsubcalls, shift_style);
2568 break;
2569 case SYS_semsys:
2570 decode_subcall(tcp, SYS_semsys_subcall,
2571 SYS_semsys_nsubcalls, shift_style);
2572 break;
2573#if 0 /* broken */
2574 case SYS_utssys:
2575 decode_subcall(tcp, SYS_utssys_subcall,
2576 SYS_utssys_nsubcalls, shift_style);
2577 break;
2578#endif
2579 case SYS_sysfs:
2580 decode_subcall(tcp, SYS_sysfs_subcall,
2581 SYS_sysfs_nsubcalls, shift_style);
2582 break;
2583 case SYS_spcall:
2584 decode_subcall(tcp, SYS_spcall_subcall,
2585 SYS_spcall_nsubcalls, shift_style);
2586 break;
2587#ifdef SYS_context_subcall
2588 case SYS_context:
2589 decode_subcall(tcp, SYS_context_subcall,
2590 SYS_context_nsubcalls, shift_style);
2591 break;
2592#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002593#ifdef SYS_door_subcall
2594 case SYS_door:
2595 decode_subcall(tcp, SYS_door_subcall,
2596 SYS_door_nsubcalls, door_style);
2597 break;
2598#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002599#ifdef SYS_kaio_subcall
2600 case SYS_kaio:
2601 decode_subcall(tcp, SYS_kaio_subcall,
2602 SYS_kaio_nsubcalls, shift_style);
2603 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002604#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002605#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002606#ifdef FREEBSD
2607 case SYS_msgsys:
2608 case SYS_shmsys:
2609 case SYS_semsys:
2610 decode_subcall(tcp, 0, 0, table_style);
2611 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002612#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002613#ifdef SUNOS4
2614 case SYS_semsys:
2615 decode_subcall(tcp, SYS_semsys_subcall,
2616 SYS_semsys_nsubcalls, shift_style);
2617 break;
2618 case SYS_msgsys:
2619 decode_subcall(tcp, SYS_msgsys_subcall,
2620 SYS_msgsys_nsubcalls, shift_style);
2621 break;
2622 case SYS_shmsys:
2623 decode_subcall(tcp, SYS_shmsys_subcall,
2624 SYS_shmsys_nsubcalls, shift_style);
2625 break;
2626#endif
2627 }
2628
2629 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002630 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002631 tcp->flags |= TCB_INSYSCALL;
2632 return 0;
2633 }
2634
2635 if (cflag) {
2636 gettimeofday(&tcp->etime, NULL);
2637 tcp->flags |= TCB_INSYSCALL;
2638 return 0;
2639 }
2640
2641 printleader(tcp);
2642 tcp->flags &= ~TCB_REPRINT;
2643 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002644 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002645 tprintf("syscall_%lu(", tcp->scno);
2646 else
2647 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002648 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002649 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2650 sys_res = printargs(tcp);
2651 else
2652 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2653 if (fflush(tcp->outf) == EOF)
2654 return -1;
2655 tcp->flags |= TCB_INSYSCALL;
2656 /* Measure the entrance time as late as possible to avoid errors. */
2657 if (dtime)
2658 gettimeofday(&tcp->etime, NULL);
2659 return sys_res;
2660}
2661
2662int
2663printargs(tcp)
2664struct tcb *tcp;
2665{
2666 if (entering(tcp)) {
2667 int i;
2668
2669 for (i = 0; i < tcp->u_nargs; i++)
2670 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2671 }
2672 return 0;
2673}
2674
2675long
2676getrval2(tcp)
2677struct tcb *tcp;
2678{
2679 long val = -1;
2680
2681#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002682#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002683 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002684 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2685 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002686 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002687#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002688 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002689 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002690#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002691 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002692 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002693#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694#endif /* LINUX */
2695
2696#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002697 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698 return -1;
2699#endif /* SUNOS4 */
2700
2701#ifdef SVR4
2702#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002703 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002704#endif /* SPARC */
2705#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002706 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002708#ifdef X86_64
2709 val = tcp->status.PR_REG[RDX];
2710#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002711#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002712 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713#endif /* MIPS */
2714#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002715#ifdef FREEBSD
2716 struct reg regs;
2717 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2718 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002719#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720 return val;
2721}
2722
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002723#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724/*
2725 * Apparently, indirect system calls have already be converted by ptrace(2),
2726 * so if you see "indir" this program has gone astray.
2727 */
2728int
2729sys_indir(tcp)
2730struct tcb *tcp;
2731{
2732 int i, scno, nargs;
2733
2734 if (entering(tcp)) {
2735 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2736 fprintf(stderr, "Bogus syscall: %u\n", scno);
2737 return 0;
2738 }
2739 nargs = sysent[scno].nargs;
2740 tprintf("%s", sysent[scno].sys_name);
2741 for (i = 0; i < nargs; i++)
2742 tprintf(", %#lx", tcp->u_arg[i+1]);
2743 }
2744 return 0;
2745}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002746#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002747
2748int
2749is_restart_error(struct tcb *tcp)
2750{
2751#ifdef LINUX
2752 if (!syserror(tcp))
2753 return 0;
2754 switch (tcp->u_error) {
2755 case ERESTARTSYS:
2756 case ERESTARTNOINTR:
2757 case ERESTARTNOHAND:
2758 case ERESTART_RESTARTBLOCK:
2759 return 1;
2760 default:
2761 break;
2762 }
2763#endif /* LINUX */
2764 return 0;
2765}