blob: e699c618f207f418d4a485342c83581f288bcfe2 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Roland McGrath48a035f2006-01-12 09:45:56 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000328 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000330 return 0;
331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000370 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
552#endif
553#ifdef SYS_writev
554 case SYS_writev:
555
556 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
557 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
558 break;
559#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 }
561}
562
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000564enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565#else /* FREEBSD */
566enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
567
568struct subcall {
569 int call;
570 int nsubcalls;
571 int subcalls[5];
572};
573
Roland McGratha4d48532005-06-08 20:45:28 +0000574static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000576#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000577 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000578#else
579 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
580#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
582};
583#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000584
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000585#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586
Roland McGratha4d48532005-06-08 20:45:28 +0000587static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588decode_subcall(tcp, subcall, nsubcalls, style)
589struct tcb *tcp;
590int subcall;
591int nsubcalls;
592enum subcall_style style;
593{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000594 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000595 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000596 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 switch (style) {
599 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000600 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
601 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 tcp->scno = subcall + tcp->u_arg[0];
603 if (sysent[tcp->scno].nargs != -1)
604 tcp->u_nargs = sysent[tcp->scno].nargs;
605 else
606 tcp->u_nargs--;
607 for (i = 0; i < tcp->u_nargs; i++)
608 tcp->u_arg[i] = tcp->u_arg[i + 1];
609 break;
610 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000611 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
612 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 tcp->scno = subcall + tcp->u_arg[0];
614 addr = tcp->u_arg[1];
615 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000616 if (size == sizeof(int)) {
617 unsigned int arg;
618 if (umove(tcp, addr, &arg) < 0)
619 arg = 0;
620 tcp->u_arg[i] = arg;
621 }
622 else if (size == sizeof(long)) {
623 unsigned long arg;
624 if (umove(tcp, addr, &arg) < 0)
625 arg = 0;
626 tcp->u_arg[i] = arg;
627 }
628 else
629 abort();
630 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
632 tcp->u_nargs = sysent[tcp->scno].nargs;
633 break;
634 case mask_style:
635 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 for (i = 0; mask; i++)
637 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000638 if (i >= nsubcalls)
639 return;
640 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tcp->scno = subcall + i;
642 if (sysent[tcp->scno].nargs != -1)
643 tcp->u_nargs = sysent[tcp->scno].nargs;
644 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000645 case door_style:
646 /*
647 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000648 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000649 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000650 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
651 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000652 tcp->scno = subcall + tcp->u_arg[5];
653 if (sysent[tcp->scno].nargs != -1)
654 tcp->u_nargs = sysent[tcp->scno].nargs;
655 else
656 tcp->u_nargs--;
657 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#ifdef FREEBSD
659 case table_style:
660 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
661 if (subcalls_table[i].call == tcp->scno) break;
662 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
663 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
664 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
665 for (i = 0; i < tcp->u_nargs; i++)
666 tcp->u_arg[i] = tcp->u_arg[i + 1];
667 }
668 break;
669#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 }
671}
672#endif
673
674struct tcb *tcp_last = NULL;
675
676static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678{
679 /*
680 * We must always trace a few critical system calls in order to
681 * correctly support following forks in the presence of tracing
682 * qualifiers.
683 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000684 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
687 return 0;
688
689 func = sysent[tcp->scno].sys_func;
690
691 if (sys_exit == func)
692 return internal_exit(tcp);
693
694 if ( sys_fork == func
695#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
696 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698#if UNIXWARE > 2
699 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000701 )
702 return internal_fork(tcp);
703
704#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
705 if (sys_clone == func)
706 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 if ( sys_execve == func
710#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
711 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000713#if UNIXWARE > 2
714 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000715#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000716 )
717 return internal_exec(tcp);
718
719 if ( sys_waitpid == func
720 || sys_wait4 == func
721#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
722 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000723#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000724#ifdef ALPHA
725 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000726#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000727 )
728 return internal_wait(tcp, 2);
729
730#if defined(LINUX) || defined(SVR4)
731 if (sys_waitid == func)
732 return internal_wait(tcp, 3);
733#endif
734
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 return 0;
736}
737
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738
739#ifdef LINUX
740#if defined (I386)
741 static long eax;
742#elif defined (IA64)
743 long r8, r10, psr;
744 long ia32 = 0;
745#elif defined (POWERPC)
746 static long result,flags;
747#elif defined (M68K)
748 static int d0;
749#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000750 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000751#elif defined (ALPHA)
752 static long r0;
753 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000754#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000755 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000756 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000757#elif defined(LINUX_MIPSN32)
758 static long long a3;
759 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000760#elif defined(MIPS)
761 static long a3;
762 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000763#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764 static long gpr2;
765 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000766 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000767#elif defined(HPPA)
768 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000769#elif defined(SH)
770 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000771#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000772 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000773#elif defined(X86_64)
774 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000775#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000776#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000777#ifdef FREEBSD
778 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000779#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000780
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000782get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783struct tcb *tcp;
784{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000786#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000788#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000791#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000792 if (tcp->flags & TCB_WAITEXECVE) {
793 /*
794 * When the execve system call completes successfully, the
795 * new process still has -ENOSYS (old style) or __NR_execve
796 * (new style) in gpr2. We cannot recover the scno again
797 * by disassembly, because the image that executed the
798 * syscall is gone now. Fortunately, we don't want it. We
799 * leave the flag set so that syscall_fixup can fake the
800 * result.
801 */
802 if (tcp->flags & TCB_INSYSCALL)
803 return 1;
804 /*
805 * This is the SIGTRAP after execve. We cannot try to read
806 * the system call here either.
807 */
808 tcp->flags &= ~TCB_WAITEXECVE;
809 return 0;
810 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000811
812 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
813 return -1;
814
815 if (syscall_mode != -ENOSYS) {
816 /*
817 * Since kernel version 2.5.44 the scno gets passed in gpr2.
818 */
819 scno = syscall_mode;
820 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000821 /*
822 * Old style of "passing" the scno via the SVC instruction.
823 */
824
825 long opcode, offset_reg, tmp;
826 void * svc_addr;
827 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
828 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
829 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
830 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000831
Michal Ludvig882eda82002-11-11 12:50:47 +0000832 if (upeek(pid, PT_PSWADDR, &pc) < 0)
833 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 if (errno) {
837 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000839 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000840
841 /*
842 * We have to check if the SVC got executed directly or via an
843 * EXECUTE instruction. In case of EXECUTE it is necessary to do
844 * instruction decoding to derive the system call number.
845 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
846 * so that this doesn't work if a SVC opcode is part of an EXECUTE
847 * opcode. Since there is no way to find out the opcode size this
848 * is the best we can do...
849 */
850
851 if ((opcode & 0xff00) == 0x0a00) {
852 /* SVC opcode */
853 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000854 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000855 else {
856 /* SVC got executed by EXECUTE instruction */
857
858 /*
859 * Do instruction decoding of EXECUTE. If you really want to
860 * understand this, read the Principles of Operations.
861 */
862 svc_addr = (void *) (opcode & 0xfff);
863
864 tmp = 0;
865 offset_reg = (opcode & 0x000f0000) >> 16;
866 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
867 return -1;
868 svc_addr += tmp;
869
870 tmp = 0;
871 offset_reg = (opcode & 0x0000f000) >> 12;
872 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
873 return -1;
874 svc_addr += tmp;
875
876 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
877 if (errno)
878 return -1;
879#if defined(S390X)
880 scno >>= 48;
881#else
882 scno >>= 16;
883#endif
884 tmp = 0;
885 offset_reg = (opcode & 0x00f00000) >> 20;
886 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
887 return -1;
888
889 scno = (scno | tmp) & 0xff;
890 }
891 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000892#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000893 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 return -1;
895 if (!(tcp->flags & TCB_INSYSCALL)) {
896 /* Check if we return from execve. */
897 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
898 tcp->flags &= ~TCB_WAITEXECVE;
899 return 0;
900 }
901 }
902#elif defined (I386)
903 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
904 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000905#elif defined (X86_64)
906 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
907 return -1;
908
Roland McGrath761b5d72002-12-15 23:58:31 +0000909 if (!(tcp->flags & TCB_INSYSCALL)) {
910 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 long val;
912
913 /* Check CS register value. On x86-64 linux it is:
914 * 0x33 for long mode (64 bit)
915 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000916 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 * to be cached.
918 */
919 if (upeek(pid, 8*CS, &val) < 0)
920 return -1;
921 switch(val)
922 {
923 case 0x23: currpers = 1; break;
924 case 0x33: currpers = 0; break;
925 default:
926 fprintf(stderr, "Unknown value CS=0x%02X while "
927 "detecting personality of process "
928 "PID=%d\n", (int)val, pid);
929 currpers = current_personality;
930 break;
931 }
932#if 0
933 /* This version analyzes the opcode of a syscall instruction.
934 * (int 0x80 on i386 vs. syscall on x86-64)
935 * It works, but is too complicated.
936 */
937 unsigned long val, rip, i;
938
939 if(upeek(pid, 8*RIP, &rip)<0)
940 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000941
Michal Ludvig0e035502002-09-23 15:41:01 +0000942 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
943 rip-=2;
944 errno = 0;
945
Roland McGrath761b5d72002-12-15 23:58:31 +0000946 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
947 if (errno)
948 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000949 strerror(errno));
950 switch (call & 0xffff)
951 {
952 /* x86-64: syscall = 0x0f 0x05 */
953 case 0x050f: currpers = 0; break;
954 /* i386: int 0x80 = 0xcd 0x80 */
955 case 0x80cd: currpers = 1; break;
956 default:
957 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000958 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000959 "Unknown syscall opcode (0x%04X) while "
960 "detecting personality of process "
961 "PID=%d\n", (int)call, pid);
962 break;
963 }
964#endif
965 if(currpers != current_personality)
966 {
967 char *names[]={"64 bit", "32 bit"};
968 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000969 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 pid, names[current_personality]);
971 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000972 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000973#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000974# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000976 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000977 if (!(tcp->flags & TCB_INSYSCALL)) {
978 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000979 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980 return -1;
981 } else {
982 if (upeek (pid, PT_R15, &scno) < 0)
983 return -1;
984 }
Roland McGrathba954762003-03-05 06:29:06 +0000985 /* Check if we return from execve. */
986 if (tcp->flags & TCB_WAITEXECVE) {
987 tcp->flags &= ~TCB_WAITEXECVE;
988 return 0;
989 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000990 } else {
991 /* syscall in progress */
992 if (upeek (pid, PT_R8, &r8) < 0)
993 return -1;
994 if (upeek (pid, PT_R10, &r10) < 0)
995 return -1;
996 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000997#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000998 /*
999 * Read complete register set in one go.
1000 */
1001 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1002 return -1;
1003
1004 /*
1005 * We only need to grab the syscall number on syscall entry.
1006 */
1007 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001008 if (!(tcp->flags & TCB_INSYSCALL)) {
1009 /* Check if we return from execve. */
1010 if (tcp->flags & TCB_WAITEXECVE) {
1011 tcp->flags &= ~TCB_WAITEXECVE;
1012 return 0;
1013 }
1014 }
1015
Roland McGrath0f87c492003-06-03 23:29:04 +00001016 /*
1017 * Note: we only deal with only 32-bit CPUs here.
1018 */
1019 if (regs.ARM_cpsr & 0x20) {
1020 /*
1021 * Get the Thumb-mode system call number
1022 */
1023 scno = regs.ARM_r7;
1024 } else {
1025 /*
1026 * Get the ARM-mode system call number
1027 */
1028 errno = 0;
1029 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1030 if (errno)
1031 return -1;
1032
1033 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1034 tcp->flags &= ~TCB_WAITEXECVE;
1035 return 0;
1036 }
1037
Roland McGrathf691bd22006-04-25 07:34:41 +00001038 /* Handle the EABI syscall convention. We do not
1039 bother converting structures between the two
1040 ABIs, but basic functionality should work even
1041 if strace and the traced program have different
1042 ABIs. */
1043 if (scno == 0xef000000) {
1044 scno = regs.ARM_r7;
1045 } else {
1046 if ((scno & 0x0ff00000) != 0x0f900000) {
1047 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1048 scno);
1049 return -1;
1050 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001051
Roland McGrathf691bd22006-04-25 07:34:41 +00001052 /*
1053 * Fixup the syscall number
1054 */
1055 scno &= 0x000fffff;
1056 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001057 }
1058
1059 if (tcp->flags & TCB_INSYSCALL) {
1060 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1061 tcp->flags &= ~TCB_INSYSCALL;
1062 }
1063 } else {
1064 if (!(tcp->flags & TCB_INSYSCALL)) {
1065 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1066 tcp->flags |= TCB_INSYSCALL;
1067 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068 }
1069#elif defined (M68K)
1070 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1071 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001072#elif defined (LINUX_MIPSN32)
1073 unsigned long long regs[38];
1074
1075 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1076 return -1;
1077 a3 = regs[REG_A3];
1078 r2 = regs[REG_V0];
1079
1080 if(!(tcp->flags & TCB_INSYSCALL)) {
1081 scno = r2;
1082
1083 /* Check if we return from execve. */
1084 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1085 tcp->flags &= ~TCB_WAITEXECVE;
1086 return 0;
1087 }
1088
1089 if (scno < 0 || scno > nsyscalls) {
1090 if(a3 == 0 || a3 == -1) {
1091 if(debug)
1092 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1093 return 0;
1094 }
1095 }
1096 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001097#elif defined (MIPS)
1098 if (upeek(pid, REG_A3, &a3) < 0)
1099 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001100 if(!(tcp->flags & TCB_INSYSCALL)) {
1101 if (upeek(pid, REG_V0, &scno) < 0)
1102 return -1;
1103
Roland McGrath542c2c62008-05-20 01:11:56 +00001104 /* Check if we return from execve. */
1105 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1106 tcp->flags &= ~TCB_WAITEXECVE;
1107 return 0;
1108 }
1109
Wichert Akkermanf90da011999-10-31 21:15:38 +00001110 if (scno < 0 || scno > nsyscalls) {
1111 if(a3 == 0 || a3 == -1) {
1112 if(debug)
1113 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1114 return 0;
1115 }
1116 }
1117 } else {
1118 if (upeek(pid, REG_V0, &r2) < 0)
1119 return -1;
1120 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121#elif defined (ALPHA)
1122 if (upeek(pid, REG_A3, &a3) < 0)
1123 return -1;
1124
1125 if (!(tcp->flags & TCB_INSYSCALL)) {
1126 if (upeek(pid, REG_R0, &scno) < 0)
1127 return -1;
1128
1129 /* Check if we return from execve. */
1130 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1131 tcp->flags &= ~TCB_WAITEXECVE;
1132 return 0;
1133 }
1134
1135 /*
1136 * Do some sanity checks to figure out if it's
1137 * really a syscall entry
1138 */
1139 if (scno < 0 || scno > nsyscalls) {
1140 if (a3 == 0 || a3 == -1) {
1141 if (debug)
1142 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1143 return 0;
1144 }
1145 }
1146 }
1147 else {
1148 if (upeek(pid, REG_R0, &r0) < 0)
1149 return -1;
1150 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001151#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 /* Everything we need is in the current register set. */
1153 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1154 return -1;
1155
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 /* If we are entering, then disassemble the syscall trap. */
1157 if (!(tcp->flags & TCB_INSYSCALL)) {
1158 /* Retrieve the syscall trap instruction. */
1159 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001160 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001161#if defined(SPARC64)
1162 trap >>= 32;
1163#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 if (errno)
1165 return -1;
1166
1167 /* Disassemble the trap to see what personality to use. */
1168 switch (trap) {
1169 case 0x91d02010:
1170 /* Linux/SPARC syscall trap. */
1171 set_personality(0);
1172 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001173 case 0x91d0206d:
1174 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001175 set_personality(2);
1176 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 case 0x91d02000:
1178 /* SunOS syscall trap. (pers 1) */
1179 fprintf(stderr,"syscall: SunOS no support\n");
1180 return -1;
1181 case 0x91d02008:
1182 /* Solaris 2.x syscall trap. (per 2) */
1183 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001184 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 case 0x91d02009:
1186 /* NetBSD/FreeBSD syscall trap. */
1187 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1188 return -1;
1189 case 0x91d02027:
1190 /* Solaris 2.x gettimeofday */
1191 set_personality(1);
1192 break;
1193 default:
1194 /* Unknown syscall trap. */
1195 if(tcp->flags & TCB_WAITEXECVE) {
1196 tcp->flags &= ~TCB_WAITEXECVE;
1197 return 0;
1198 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001199#if defined (SPARC64)
1200 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1201#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001202 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001203#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204 return -1;
1205 }
1206
1207 /* Extract the system call number from the registers. */
1208 if (trap == 0x91d02027)
1209 scno = 156;
1210 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001211 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001213 scno = regs.r_o0;
1214 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 }
1216 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001217#elif defined(HPPA)
1218 if (upeek(pid, PT_GR20, &scno) < 0)
1219 return -1;
1220 if (!(tcp->flags & TCB_INSYSCALL)) {
1221 /* Check if we return from execve. */
1222 if ((tcp->flags & TCB_WAITEXECVE)) {
1223 tcp->flags &= ~TCB_WAITEXECVE;
1224 return 0;
1225 }
1226 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001227#elif defined(SH)
1228 /*
1229 * In the new syscall ABI, the system call number is in R3.
1230 */
1231 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1232 return -1;
1233
1234 if (scno < 0) {
1235 /* Odd as it may seem, a glibc bug has been known to cause
1236 glibc to issue bogus negative syscall numbers. So for
1237 our purposes, make strace print what it *should* have been */
1238 long correct_scno = (scno & 0xff);
1239 if (debug)
1240 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001241 "Detected glibc bug: bogus system call number = %ld, "
1242 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001243 scno,
1244 correct_scno);
1245 scno = correct_scno;
1246 }
1247
1248
1249 if (!(tcp->flags & TCB_INSYSCALL)) {
1250 /* Check if we return from execve. */
1251 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1252 tcp->flags &= ~TCB_WAITEXECVE;
1253 return 0;
1254 }
1255 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001256#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001257 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1258 return -1;
1259 scno &= 0xFFFF;
1260
1261 if (!(tcp->flags & TCB_INSYSCALL)) {
1262 /* Check if we return from execve. */
1263 if (tcp->flags & TCB_WAITEXECVE) {
1264 tcp->flags &= ~TCB_WAITEXECVE;
1265 return 0;
1266 }
1267 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001268#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269#endif /* LINUX */
1270#ifdef SUNOS4
1271 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1272 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001273#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001274 /* new syscall ABI returns result in R0 */
1275 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1276 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001277#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001278 /* ABI defines result returned in r9 */
1279 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1280 return -1;
1281
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001283#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001285 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001287#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001288 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001289#else /* FREEBSD */
1290 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1291 perror("pread");
1292 return -1;
1293 }
1294 switch (regs.r_eax) {
1295 case SYS_syscall:
1296 case SYS___syscall:
1297 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1298 break;
1299 default:
1300 scno = regs.r_eax;
1301 break;
1302 }
1303#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001305#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001306 if (!(tcp->flags & TCB_INSYSCALL))
1307 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001308 return 1;
1309}
1310
Pavel Machek4dc3b142000-02-01 17:58:41 +00001311
Roland McGrath17352792005-06-07 23:21:26 +00001312long
1313known_scno(tcp)
1314struct tcb *tcp;
1315{
1316 long scno = tcp->scno;
1317 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1318 scno = sysent[scno].native_scno;
1319 else
1320 scno += NR_SYSCALL_BASE;
1321 return scno;
1322}
1323
Roland McGratha4d48532005-06-08 20:45:28 +00001324static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001325syscall_fixup(tcp)
1326struct tcb *tcp;
1327{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001328#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001329 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001330#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001331 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001332
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 if (
1336 scno == SYS_fork
1337#ifdef SYS_vfork
1338 || scno == SYS_vfork
1339#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001340#ifdef SYS_fork1
1341 || scno == SYS_fork1
1342#endif /* SYS_fork1 */
1343#ifdef SYS_forkall
1344 || scno == SYS_forkall
1345#endif /* SYS_forkall */
1346#ifdef SYS_rfork1
1347 || scno == SYS_rfork1
1348#endif /* SYS_fork1 */
1349#ifdef SYS_rforkall
1350 || scno == SYS_rforkall
1351#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352 ) {
1353 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001354 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001355 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001356 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 }
1358 else {
1359 fprintf(stderr, "syscall: missing entry\n");
1360 tcp->flags |= TCB_INSYSCALL;
1361 }
1362 }
1363 }
1364 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001365 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 fprintf(stderr, "syscall: missing exit\n");
1367 tcp->flags &= ~TCB_INSYSCALL;
1368 }
1369 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371#ifdef SUNOS4
1372 if (!(tcp->flags & TCB_INSYSCALL)) {
1373 if (scno == 0) {
1374 fprintf(stderr, "syscall: missing entry\n");
1375 tcp->flags |= TCB_INSYSCALL;
1376 }
1377 }
1378 else {
1379 if (scno != 0) {
1380 if (debug) {
1381 /*
1382 * This happens when a signal handler
1383 * for a signal which interrupted a
1384 * a system call makes another system call.
1385 */
1386 fprintf(stderr, "syscall: missing exit\n");
1387 }
1388 tcp->flags &= ~TCB_INSYSCALL;
1389 }
1390 }
1391#endif /* SUNOS4 */
1392#ifdef LINUX
1393#if defined (I386)
1394 if (upeek(pid, 4*EAX, &eax) < 0)
1395 return -1;
1396 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1397 if (debug)
1398 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1399 return 0;
1400 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001401#elif defined (X86_64)
1402 if (upeek(pid, 8*RAX, &rax) < 0)
1403 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001404 if (current_personality == 1)
1405 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001406 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1407 if (debug)
1408 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1409 return 0;
1410 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001411#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001412 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1413 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001414 if (syscall_mode != -ENOSYS)
1415 syscall_mode = tcp->scno;
1416 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001417 if (debug)
1418 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1419 return 0;
1420 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001421 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1422 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1423 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1424 /*
1425 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1426 * flag set for the post-execve SIGTRAP to see and reset.
1427 */
1428 gpr2 = 0;
1429 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430#elif defined (POWERPC)
1431# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001432 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001433 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001434 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 return -1;
1436 if (flags & SO_MASK)
1437 result = -result;
1438#elif defined (M68K)
1439 if (upeek(pid, 4*PT_D0, &d0) < 0)
1440 return -1;
1441 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1442 if (debug)
1443 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1444 return 0;
1445 }
1446#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001447 /*
1448 * Nothing required
1449 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001450#elif defined (HPPA)
1451 if (upeek(pid, PT_GR28, &r28) < 0)
1452 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001453#elif defined(IA64)
1454 if (upeek(pid, PT_R10, &r10) < 0)
1455 return -1;
1456 if (upeek(pid, PT_R8, &r8) < 0)
1457 return -1;
1458 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1459 if (debug)
1460 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1461 return 0;
1462 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463#endif
1464#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001465 return 1;
1466}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467
Roland McGratha4d48532005-06-08 20:45:28 +00001468static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001469get_error(tcp)
1470struct tcb *tcp;
1471{
1472 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001474#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001475 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1476 tcp->u_rval = -1;
1477 u_error = -gpr2;
1478 }
1479 else {
1480 tcp->u_rval = gpr2;
1481 u_error = 0;
1482 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001483#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484#ifdef I386
1485 if (eax < 0 && -eax < nerrnos) {
1486 tcp->u_rval = -1;
1487 u_error = -eax;
1488 }
1489 else {
1490 tcp->u_rval = eax;
1491 u_error = 0;
1492 }
1493#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001494#ifdef X86_64
1495 if (rax < 0 && -rax < nerrnos) {
1496 tcp->u_rval = -1;
1497 u_error = -rax;
1498 }
1499 else {
1500 tcp->u_rval = rax;
1501 u_error = 0;
1502 }
1503#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001504#ifdef IA64
1505 if (ia32) {
1506 int err;
1507
1508 err = (int)r8;
1509 if (err < 0 && -err < nerrnos) {
1510 tcp->u_rval = -1;
1511 u_error = -err;
1512 }
1513 else {
1514 tcp->u_rval = err;
1515 u_error = 0;
1516 }
1517 } else {
1518 if (r10) {
1519 tcp->u_rval = -1;
1520 u_error = r8;
1521 } else {
1522 tcp->u_rval = r8;
1523 u_error = 0;
1524 }
1525 }
1526#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001527#ifdef MIPS
1528 if (a3) {
1529 tcp->u_rval = -1;
1530 u_error = r2;
1531 } else {
1532 tcp->u_rval = r2;
1533 u_error = 0;
1534 }
1535#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001536#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001537 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001538 tcp->u_rval = -1;
1539 u_error = -result;
1540 }
1541 else {
1542 tcp->u_rval = result;
1543 u_error = 0;
1544 }
1545#else /* !POWERPC */
1546#ifdef M68K
1547 if (d0 && (unsigned) -d0 < nerrnos) {
1548 tcp->u_rval = -1;
1549 u_error = -d0;
1550 }
1551 else {
1552 tcp->u_rval = d0;
1553 u_error = 0;
1554 }
1555#else /* !M68K */
1556#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001557 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001559 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001560 }
1561 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001562 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001563 u_error = 0;
1564 }
1565#else /* !ARM */
1566#ifdef ALPHA
1567 if (a3) {
1568 tcp->u_rval = -1;
1569 u_error = r0;
1570 }
1571 else {
1572 tcp->u_rval = r0;
1573 u_error = 0;
1574 }
1575#else /* !ALPHA */
1576#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001577 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001578 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001579 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580 }
1581 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001582 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 u_error = 0;
1584 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001585#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001586#ifdef SPARC64
1587 if (regs.r_tstate & 0x1100000000UL) {
1588 tcp->u_rval = -1;
1589 u_error = regs.r_o0;
1590 }
1591 else {
1592 tcp->u_rval = regs.r_o0;
1593 u_error = 0;
1594 }
1595#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001596#ifdef HPPA
1597 if (r28 && (unsigned) -r28 < nerrnos) {
1598 tcp->u_rval = -1;
1599 u_error = -r28;
1600 }
1601 else {
1602 tcp->u_rval = r28;
1603 u_error = 0;
1604 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001605#else
1606#ifdef SH
1607 /* interpret R0 as return value or error number */
1608 if (r0 && (unsigned) -r0 < nerrnos) {
1609 tcp->u_rval = -1;
1610 u_error = -r0;
1611 }
1612 else {
1613 tcp->u_rval = r0;
1614 u_error = 0;
1615 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001616#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001617#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001618 /* interpret result as return value or error number */
1619 if (r9 && (unsigned) -r9 < nerrnos) {
1620 tcp->u_rval = -1;
1621 u_error = -r9;
1622 }
1623 else {
1624 tcp->u_rval = r9;
1625 u_error = 0;
1626 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001627#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001628#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001629#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001631#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632#endif /* ALPHA */
1633#endif /* ARM */
1634#endif /* M68K */
1635#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001636#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001637#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001638#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001640#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641#endif /* LINUX */
1642#ifdef SUNOS4
1643 /* get error code from user struct */
1644 if (upeek(pid, uoff(u_error), &u_error) < 0)
1645 return -1;
1646 u_error >>= 24; /* u_error is a char */
1647
1648 /* get system call return value */
1649 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1650 return -1;
1651#endif /* SUNOS4 */
1652#ifdef SVR4
1653#ifdef SPARC
1654 /* Judicious guessing goes a long way. */
1655 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1656 tcp->u_rval = -1;
1657 u_error = tcp->status.pr_reg[R_O0];
1658 }
1659 else {
1660 tcp->u_rval = tcp->status.pr_reg[R_O0];
1661 u_error = 0;
1662 }
1663#endif /* SPARC */
1664#ifdef I386
1665 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001666 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001668 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 }
1670 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001671 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001672#ifdef HAVE_LONG_LONG
1673 tcp->u_lrval =
1674 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1675 tcp->status.PR_REG[EAX];
1676#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 u_error = 0;
1678 }
1679#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001680#ifdef X86_64
1681 /* Wanna know how to kill an hour single-stepping? */
1682 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1683 tcp->u_rval = -1;
1684 u_error = tcp->status.PR_REG[RAX];
1685 }
1686 else {
1687 tcp->u_rval = tcp->status.PR_REG[RAX];
1688 u_error = 0;
1689 }
1690#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691#ifdef MIPS
1692 if (tcp->status.pr_reg[CTX_A3]) {
1693 tcp->u_rval = -1;
1694 u_error = tcp->status.pr_reg[CTX_V0];
1695 }
1696 else {
1697 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1698 u_error = 0;
1699 }
1700#endif /* MIPS */
1701#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001702#ifdef FREEBSD
1703 if (regs.r_eflags & PSL_C) {
1704 tcp->u_rval = -1;
1705 u_error = regs.r_eax;
1706 } else {
1707 tcp->u_rval = regs.r_eax;
1708 tcp->u_lrval =
1709 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1710 u_error = 0;
1711 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001712#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001713 tcp->u_error = u_error;
1714 return 1;
1715}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716
Roland McGrathb69f81b2002-12-21 23:25:18 +00001717int
1718force_result(tcp, error, rval)
1719 struct tcb *tcp;
1720 int error;
1721 long rval;
1722{
1723#ifdef LINUX
1724#if defined(S390) || defined(S390X)
1725 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001726 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1727 return -1;
1728#else /* !S390 && !S390X */
1729#ifdef I386
1730 eax = error ? -error : rval;
1731 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1732 return -1;
1733#else /* !I386 */
1734#ifdef X86_64
1735 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001736 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001737 return -1;
1738#else
1739#ifdef IA64
1740 if (ia32) {
1741 r8 = error ? -error : rval;
1742 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1743 return -1;
1744 }
1745 else {
1746 if (error) {
1747 r8 = error;
1748 r10 = -1;
1749 }
1750 else {
1751 r8 = rval;
1752 r10 = 0;
1753 }
1754 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1755 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1756 return -1;
1757 }
1758#else /* !IA64 */
1759#ifdef MIPS
1760 if (error) {
1761 r2 = error;
1762 a3 = -1;
1763 }
1764 else {
1765 r2 = rval;
1766 a3 = 0;
1767 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001768 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001769 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1770 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1771 return -1;
1772#else
1773#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001774 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001775 return -1;
1776 if (error) {
1777 flags |= SO_MASK;
1778 result = error;
1779 }
1780 else {
1781 flags &= ~SO_MASK;
1782 result = rval;
1783 }
Roland McGratheb285352003-01-14 09:59:00 +00001784 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1785 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786 return -1;
1787#else /* !POWERPC */
1788#ifdef M68K
1789 d0 = error ? -error : rval;
1790 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1791 return -1;
1792#else /* !M68K */
1793#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001794 regs.ARM_r0 = error ? -error : rval;
1795 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796 return -1;
1797#else /* !ARM */
1798#ifdef ALPHA
1799 if (error) {
1800 a3 = -1;
1801 r0 = error;
1802 }
1803 else {
1804 a3 = 0;
1805 r0 = rval;
1806 }
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1808 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1809 return -1;
1810#else /* !ALPHA */
1811#ifdef SPARC
1812 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1813 return -1;
1814 if (error) {
1815 regs.r_psr |= PSR_C;
1816 regs.r_o0 = error;
1817 }
1818 else {
1819 regs.r_psr &= ~PSR_C;
1820 regs.r_o0 = rval;
1821 }
1822 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1823 return -1;
1824#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001825#ifdef SPARC64
1826 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1827 return -1;
1828 if (error) {
1829 regs.r_tstate |= 0x1100000000UL;
1830 regs.r_o0 = error;
1831 }
1832 else {
1833 regs.r_tstate &= ~0x1100000000UL;
1834 regs.r_o0 = rval;
1835 }
1836 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1837 return -1;
1838#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001839#ifdef HPPA
1840 r28 = error ? -error : rval;
1841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1842 return -1;
1843#else
1844#ifdef SH
1845 r0 = error ? -error : rval;
1846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1847 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001848#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001849#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001850 r9 = error ? -error : rval;
1851 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1852 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001853#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854#endif /* SH */
1855#endif /* HPPA */
1856#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001857#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001858#endif /* ALPHA */
1859#endif /* ARM */
1860#endif /* M68K */
1861#endif /* POWERPC */
1862#endif /* MIPS */
1863#endif /* IA64 */
1864#endif /* X86_64 */
1865#endif /* I386 */
1866#endif /* S390 || S390X */
1867#endif /* LINUX */
1868#ifdef SUNOS4
1869 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1870 error << 24) < 0 ||
1871 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1872 return -1;
1873#endif /* SUNOS4 */
1874#ifdef SVR4
1875 /* XXX no clue */
1876 return -1;
1877#endif /* SVR4 */
1878#ifdef FREEBSD
1879 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1880 perror("pread");
1881 return -1;
1882 }
1883 if (error) {
1884 regs.r_eflags |= PSL_C;
1885 regs.r_eax = error;
1886 }
1887 else {
1888 regs.r_eflags &= ~PSL_C;
1889 regs.r_eax = rval;
1890 }
1891 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1892 perror("pwrite");
1893 return -1;
1894 }
1895#endif /* FREEBSD */
1896
1897 /* All branches reach here on success (only). */
1898 tcp->u_error = error;
1899 tcp->u_rval = rval;
1900 return 0;
1901}
1902
Roland McGratha4d48532005-06-08 20:45:28 +00001903static int
1904syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001905struct tcb *tcp;
1906{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001907#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001908 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001909#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001910#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001911#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001912 {
1913 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001914 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1915 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001916 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001917 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001918 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001919 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001920 return -1;
1921 }
1922 }
1923#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 {
1925 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001926 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1927 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001928 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001929 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001930 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001931 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1932 * for scno somewhere above here!
1933 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001934 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1935 return -1;
1936 }
1937 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001938#elif defined (IA64)
1939 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001940 if (!ia32) {
1941 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1942 /* be backwards compatible with kernel < 2.4.4... */
1943# ifndef PT_RBS_END
1944# define PT_RBS_END PT_AR_BSP
1945# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001946
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001947 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001948 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001949 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1950 return -1;
1951
1952 sof = (cfm >> 0) & 0x7f;
1953 sol = (cfm >> 7) & 0x7f;
1954 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1955
1956 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1957 && sysent[tcp->scno].nargs != -1)
1958 tcp->u_nargs = sysent[tcp->scno].nargs;
1959 else
1960 tcp->u_nargs = MAX_ARGS;
1961 for (i = 0; i < tcp->u_nargs; ++i) {
1962 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1963 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1964 return -1;
1965 }
1966 } else {
1967 int i;
1968
1969 if (/* EBX = out0 */
1970 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1971 /* ECX = out1 */
1972 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1973 /* EDX = out2 */
1974 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1975 /* ESI = out3 */
1976 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1977 /* EDI = out4 */
1978 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1979 /* EBP = out5 */
1980 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1981 return -1;
1982
1983 for (i = 0; i < 6; ++i)
1984 /* truncate away IVE sign-extension */
1985 tcp->u_arg[i] &= 0xffffffff;
1986
1987 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1988 && sysent[tcp->scno].nargs != -1)
1989 tcp->u_nargs = sysent[tcp->scno].nargs;
1990 else
1991 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001992 }
1993 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001994#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
1995 /* N32 and N64 both use up to six registers. */
1996 {
1997 unsigned long long regs[38];
1998 int i, nargs;
1999
2000 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2001 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2002 else
2003 nargs = tcp->u_nargs = MAX_ARGS;
2004
2005 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2006 return -1;
2007
2008 for(i = 0; i < nargs; i++) {
2009 tcp->u_arg[i] = regs[REG_A0 + i];
2010# if defined (LINUX_MIPSN32)
2011 tcp->ext_arg[i] = regs[REG_A0 + i];
2012# endif
2013 }
2014 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002015#elif defined (MIPS)
2016 {
2017 long sp;
2018 int i, nargs;
2019
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002020 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2021 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002022 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002023 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002024 if(nargs > 4) {
2025 if(upeek(pid, REG_SP, &sp) < 0)
2026 return -1;
2027 for(i = 0; i < 4; i++) {
2028 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2029 return -1;
2030 }
2031 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2032 (char *)(tcp->u_arg + 4));
2033 } else {
2034 for(i = 0; i < nargs; i++) {
2035 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2036 return -1;
2037 }
2038 }
2039 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002040#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002041#ifndef PT_ORIG_R3
2042#define PT_ORIG_R3 34
2043#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002044 {
2045 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002046 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2047 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002048 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002049 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002050 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002051 if (upeek(pid, (i==0) ?
2052 (sizeof(unsigned long)*PT_ORIG_R3) :
2053 ((i+PT_R3)*sizeof(unsigned long)),
2054 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002055 return -1;
2056 }
2057 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002058#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002059 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002060 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002061
2062 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2063 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002064 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002065 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002066 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002067 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002068 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002069#elif defined (HPPA)
2070 {
2071 int i;
2072
2073 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2074 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002075 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002076 tcp->u_nargs = MAX_ARGS;
2077 for (i = 0; i < tcp->u_nargs; i++) {
2078 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2079 return -1;
2080 }
2081 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002082#elif defined(ARM)
2083 {
2084 int i;
2085
2086 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2087 tcp->u_nargs = sysent[tcp->scno].nargs;
2088 else
2089 tcp->u_nargs = MAX_ARGS;
2090 for (i = 0; i < tcp->u_nargs; i++)
2091 tcp->u_arg[i] = regs.uregs[i];
2092 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002093#elif defined(SH)
2094 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002095 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002096 static int syscall_regs[] = {
2097 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2098 REG_REG0, REG_REG0+1, REG_REG0+2
2099 };
2100
2101 tcp->u_nargs = sysent[tcp->scno].nargs;
2102 for (i = 0; i < tcp->u_nargs; i++) {
2103 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2104 return -1;
2105 }
2106 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002107#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002108 {
2109 int i;
2110 /* Registers used by SH5 Linux system calls for parameters */
2111 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2112
2113 /*
2114 * TODO: should also check that the number of arguments encoded
2115 * in the trap number matches the number strace expects.
2116 */
2117 /*
2118 assert(sysent[tcp->scno].nargs <
2119 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2120 */
2121
2122 tcp->u_nargs = sysent[tcp->scno].nargs;
2123 for (i = 0; i < tcp->u_nargs; i++) {
2124 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2125 return -1;
2126 }
2127 }
2128
Michal Ludvig0e035502002-09-23 15:41:01 +00002129#elif defined(X86_64)
2130 {
2131 int i;
2132 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2133 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002134 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002135 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002136
Michal Ludvig0e035502002-09-23 15:41:01 +00002137 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2138 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002139 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002140 tcp->u_nargs = MAX_ARGS;
2141 for (i = 0; i < tcp->u_nargs; i++) {
2142 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2143 return -1;
2144 }
2145 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002146#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002147 {
2148 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002149 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2150 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002151 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002152 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002153 for (i = 0; i < tcp->u_nargs; i++) {
2154 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2155 return -1;
2156 }
2157 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002158#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002159#endif /* LINUX */
2160#ifdef SUNOS4
2161 {
2162 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002163 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2164 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002165 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002166 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002167 for (i = 0; i < tcp->u_nargs; i++) {
2168 struct user *u;
2169
2170 if (upeek(pid, uoff(u_arg[0]) +
2171 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2172 return -1;
2173 }
2174 }
2175#endif /* SUNOS4 */
2176#ifdef SVR4
2177#ifdef MIPS
2178 /*
2179 * SGI is broken: even though it has pr_sysarg, it doesn't
2180 * set them on system call entry. Get a clue.
2181 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002182 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002183 tcp->u_nargs = sysent[tcp->scno].nargs;
2184 else
2185 tcp->u_nargs = tcp->status.pr_nsysarg;
2186 if (tcp->u_nargs > 4) {
2187 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2188 4*sizeof(tcp->u_arg[0]));
2189 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2190 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2191 }
2192 else {
2193 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2194 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2195 }
John Hughes25299712001-03-06 10:10:06 +00002196#elif UNIXWARE >= 2
2197 /*
2198 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2199 */
2200 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2201 tcp->u_nargs = sysent[tcp->scno].nargs;
2202 else
2203 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2204 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2205 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2206#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002207 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002208 tcp->u_nargs = sysent[tcp->scno].nargs;
2209 else
2210 tcp->u_nargs = tcp->status.pr_nsysarg;
2211 {
2212 int i;
2213 for (i = 0; i < tcp->u_nargs; i++)
2214 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2215 }
John Hughes25299712001-03-06 10:10:06 +00002216#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002217 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002218 tcp->u_nargs = sysent[tcp->scno].nargs;
2219 else
2220 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002221 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002222 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002223#else
2224 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002225#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002227#ifdef FREEBSD
2228 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2229 sysent[tcp->scno].nargs > tcp->status.val)
2230 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002231 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002232 tcp->u_nargs = tcp->status.val;
2233 if (tcp->u_nargs < 0)
2234 tcp->u_nargs = 0;
2235 if (tcp->u_nargs > MAX_ARGS)
2236 tcp->u_nargs = MAX_ARGS;
2237 switch(regs.r_eax) {
2238 case SYS___syscall:
2239 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2240 regs.r_esp + sizeof(int) + sizeof(quad_t));
2241 break;
2242 case SYS_syscall:
2243 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2244 regs.r_esp + 2 * sizeof(int));
2245 break;
2246 default:
2247 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2248 regs.r_esp + sizeof(int));
2249 break;
2250 }
2251#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002252 return 1;
2253}
2254
2255int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002256trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002257{
2258 int sys_res;
2259 struct timeval tv;
2260 int res;
2261
2262 /* Measure the exit time as early as possible to avoid errors. */
2263 if (dtime && (tcp->flags & TCB_INSYSCALL))
2264 gettimeofday(&tv, NULL);
2265
2266 res = get_scno(tcp);
2267 if (res != 1)
2268 return res;
2269
2270 res = syscall_fixup(tcp);
2271 if (res != 1)
2272 return res;
2273
2274 if (tcp->flags & TCB_INSYSCALL) {
2275 long u_error;
2276 res = get_error(tcp);
2277 if (res != 1)
2278 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002279
2280 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002281 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2282 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002283 tcp->flags &= ~TCB_INSYSCALL;
2284 return 0;
2285 }
2286
2287 if (tcp->flags & TCB_REPRINT) {
2288 printleader(tcp);
2289 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002290 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002291 tprintf("syscall_%lu", tcp->scno);
2292 else
2293 tprintf("%s", sysent[tcp->scno].sys_name);
2294 tprintf(" resumed> ");
2295 }
2296
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002297 if (cflag)
2298 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002299
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002300 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002301 || (qual_flags[tcp->scno] & QUAL_RAW))
2302 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002303 else {
2304 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002305 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002306 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002307 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002308 u_error = tcp->u_error;
2309 tprintf(") ");
2310 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002311 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2312 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002313 if (u_error)
2314 tprintf("= -1 (errno %ld)", u_error);
2315 else
2316 tprintf("= %#lx", tcp->u_rval);
2317 }
2318 else if (!(sys_res & RVAL_NONE) && u_error) {
2319 switch (u_error) {
2320#ifdef LINUX
2321 case ERESTARTSYS:
2322 tprintf("= ? ERESTARTSYS (To be restarted)");
2323 break;
2324 case ERESTARTNOINTR:
2325 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2326 break;
2327 case ERESTARTNOHAND:
2328 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2329 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002330 case ERESTART_RESTARTBLOCK:
2331 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2332 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002333#endif /* LINUX */
2334 default:
2335 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002336 if (u_error < 0)
2337 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002339 tprintf("%s (%s)", errnoent[u_error],
2340 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002341 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002342 tprintf("ERRNO_%ld (%s)", u_error,
2343 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002344 break;
2345 }
2346 }
2347 else {
2348 if (sys_res & RVAL_NONE)
2349 tprintf("= ?");
2350 else {
2351 switch (sys_res & RVAL_MASK) {
2352 case RVAL_HEX:
2353 tprintf("= %#lx", tcp->u_rval);
2354 break;
2355 case RVAL_OCTAL:
2356 tprintf("= %#lo", tcp->u_rval);
2357 break;
2358 case RVAL_UDECIMAL:
2359 tprintf("= %lu", tcp->u_rval);
2360 break;
2361 case RVAL_DECIMAL:
2362 tprintf("= %ld", tcp->u_rval);
2363 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002364#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002365 case RVAL_LHEX:
2366 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002367 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002368 case RVAL_LOCTAL:
2369 tprintf("= %#llo", tcp->u_lrval);
2370 break;
2371 case RVAL_LUDECIMAL:
2372 tprintf("= %llu", tcp->u_lrval);
2373 break;
2374 case RVAL_LDECIMAL:
2375 tprintf("= %lld", tcp->u_lrval);
2376 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002377#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002378 default:
2379 fprintf(stderr,
2380 "invalid rval format\n");
2381 break;
2382 }
2383 }
2384 if ((sys_res & RVAL_STR) && tcp->auxstr)
2385 tprintf(" (%s)", tcp->auxstr);
2386 }
2387 if (dtime) {
2388 tv_sub(&tv, &tv, &tcp->etime);
2389 tprintf(" <%ld.%06ld>",
2390 (long) tv.tv_sec, (long) tv.tv_usec);
2391 }
2392 printtrailer(tcp);
2393
2394 dumpio(tcp);
2395 if (fflush(tcp->outf) == EOF)
2396 return -1;
2397 tcp->flags &= ~TCB_INSYSCALL;
2398 return 0;
2399 }
2400
2401 /* Entering system call */
2402 res = syscall_enter(tcp);
2403 if (res != 1)
2404 return res;
2405
Roland McGrath17352792005-06-07 23:21:26 +00002406 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002407#ifdef LINUX
Roland McGrath5e48c542008-05-19 23:50:24 +00002408#if !defined (ALPHA) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002409 case SYS_socketcall:
2410 decode_subcall(tcp, SYS_socket_subcall,
2411 SYS_socket_nsubcalls, deref_style);
2412 break;
2413 case SYS_ipc:
2414 decode_subcall(tcp, SYS_ipc_subcall,
2415 SYS_ipc_nsubcalls, shift_style);
2416 break;
Roland McGrath5e48c542008-05-19 23:50:24 +00002417#endif /* !(ALPHA || MIPS || HPPA) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002418#endif /* LINUX */
2419#ifdef SVR4
2420#ifdef SYS_pgrpsys_subcall
2421 case SYS_pgrpsys:
2422 decode_subcall(tcp, SYS_pgrpsys_subcall,
2423 SYS_pgrpsys_nsubcalls, shift_style);
2424 break;
2425#endif /* SYS_pgrpsys_subcall */
2426#ifdef SYS_sigcall_subcall
2427 case SYS_sigcall:
2428 decode_subcall(tcp, SYS_sigcall_subcall,
2429 SYS_sigcall_nsubcalls, mask_style);
2430 break;
2431#endif /* SYS_sigcall_subcall */
2432 case SYS_msgsys:
2433 decode_subcall(tcp, SYS_msgsys_subcall,
2434 SYS_msgsys_nsubcalls, shift_style);
2435 break;
2436 case SYS_shmsys:
2437 decode_subcall(tcp, SYS_shmsys_subcall,
2438 SYS_shmsys_nsubcalls, shift_style);
2439 break;
2440 case SYS_semsys:
2441 decode_subcall(tcp, SYS_semsys_subcall,
2442 SYS_semsys_nsubcalls, shift_style);
2443 break;
2444#if 0 /* broken */
2445 case SYS_utssys:
2446 decode_subcall(tcp, SYS_utssys_subcall,
2447 SYS_utssys_nsubcalls, shift_style);
2448 break;
2449#endif
2450 case SYS_sysfs:
2451 decode_subcall(tcp, SYS_sysfs_subcall,
2452 SYS_sysfs_nsubcalls, shift_style);
2453 break;
2454 case SYS_spcall:
2455 decode_subcall(tcp, SYS_spcall_subcall,
2456 SYS_spcall_nsubcalls, shift_style);
2457 break;
2458#ifdef SYS_context_subcall
2459 case SYS_context:
2460 decode_subcall(tcp, SYS_context_subcall,
2461 SYS_context_nsubcalls, shift_style);
2462 break;
2463#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002464#ifdef SYS_door_subcall
2465 case SYS_door:
2466 decode_subcall(tcp, SYS_door_subcall,
2467 SYS_door_nsubcalls, door_style);
2468 break;
2469#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002470#ifdef SYS_kaio_subcall
2471 case SYS_kaio:
2472 decode_subcall(tcp, SYS_kaio_subcall,
2473 SYS_kaio_nsubcalls, shift_style);
2474 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002475#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002476#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002477#ifdef FREEBSD
2478 case SYS_msgsys:
2479 case SYS_shmsys:
2480 case SYS_semsys:
2481 decode_subcall(tcp, 0, 0, table_style);
2482 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002483#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002484#ifdef SUNOS4
2485 case SYS_semsys:
2486 decode_subcall(tcp, SYS_semsys_subcall,
2487 SYS_semsys_nsubcalls, shift_style);
2488 break;
2489 case SYS_msgsys:
2490 decode_subcall(tcp, SYS_msgsys_subcall,
2491 SYS_msgsys_nsubcalls, shift_style);
2492 break;
2493 case SYS_shmsys:
2494 decode_subcall(tcp, SYS_shmsys_subcall,
2495 SYS_shmsys_nsubcalls, shift_style);
2496 break;
2497#endif
2498 }
2499
2500 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002501 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 tcp->flags |= TCB_INSYSCALL;
2503 return 0;
2504 }
2505
2506 if (cflag) {
2507 gettimeofday(&tcp->etime, NULL);
2508 tcp->flags |= TCB_INSYSCALL;
2509 return 0;
2510 }
2511
2512 printleader(tcp);
2513 tcp->flags &= ~TCB_REPRINT;
2514 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002515 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 tprintf("syscall_%lu(", tcp->scno);
2517 else
2518 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002519 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002520 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2521 sys_res = printargs(tcp);
2522 else
2523 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2524 if (fflush(tcp->outf) == EOF)
2525 return -1;
2526 tcp->flags |= TCB_INSYSCALL;
2527 /* Measure the entrance time as late as possible to avoid errors. */
2528 if (dtime)
2529 gettimeofday(&tcp->etime, NULL);
2530 return sys_res;
2531}
2532
2533int
2534printargs(tcp)
2535struct tcb *tcp;
2536{
2537 if (entering(tcp)) {
2538 int i;
2539
2540 for (i = 0; i < tcp->u_nargs; i++)
2541 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2542 }
2543 return 0;
2544}
2545
2546long
2547getrval2(tcp)
2548struct tcb *tcp;
2549{
2550 long val = -1;
2551
2552#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002553#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002554 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002555 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2556 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002557 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002558#elif defined(SH)
2559 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2560 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002561#elif defined(IA64)
2562 if (upeek(tcp->pid, PT_R9, &val) < 0)
2563 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002564#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002565#endif /* LINUX */
2566
2567#ifdef SUNOS4
2568 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2569 return -1;
2570#endif /* SUNOS4 */
2571
2572#ifdef SVR4
2573#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002574 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575#endif /* SPARC */
2576#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002577 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002578#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002579#ifdef X86_64
2580 val = tcp->status.PR_REG[RDX];
2581#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002582#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002583 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002584#endif /* MIPS */
2585#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002586#ifdef FREEBSD
2587 struct reg regs;
2588 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2589 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002590#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002591 return val;
2592}
2593
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002594#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002595/*
2596 * Apparently, indirect system calls have already be converted by ptrace(2),
2597 * so if you see "indir" this program has gone astray.
2598 */
2599int
2600sys_indir(tcp)
2601struct tcb *tcp;
2602{
2603 int i, scno, nargs;
2604
2605 if (entering(tcp)) {
2606 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2607 fprintf(stderr, "Bogus syscall: %u\n", scno);
2608 return 0;
2609 }
2610 nargs = sysent[scno].nargs;
2611 tprintf("%s", sysent[scno].sys_name);
2612 for (i = 0; i < nargs; i++)
2613 tprintf(", %#lx", tcp->u_arg[i+1]);
2614 }
2615 return 0;
2616}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002617#endif /* SUNOS4 */