blob: dabdd76f16a25cada8eb63311bf114e9857abbf7 [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);
327 if (i < 0 || i >= nsyscalls)
328 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 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000332 for (i = 0; i < nsyscalls; 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
339 if (strcmp(s, sysent1[i].sys_name) == 0) {
340 qualify_one(i, opt, not, 1);
341 rc = 0;
342 }
343#endif /* SUPPORTED_PERSONALITIES >= 2 */
344
345#if SUPPORTED_PERSONALITIES >= 3
346 if (strcmp(s, sysent2[i].sys_name) == 0) {
347 qualify_one(i, opt, not, 2);
348 rc = 0;
349 }
350#endif /* SUPPORTED_PERSONALITIES >= 3 */
Roland McGrath9797ceb2002-12-30 10:23:00 +0000351 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000352 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000353}
354
355static int
356qual_signal(s, opt, not)
357 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000358 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000359 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000360{
361 int i;
362 char buf[32];
363
Roland McGrath48a035f2006-01-12 09:45:56 +0000364 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000365 int signo = atoi(s);
366 if (signo < 0 || signo >= MAX_QUALS)
367 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000369 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000370 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000371 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000373 strcpy(buf, s);
374 s = buf;
375 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000376 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377 if (strncmp(s, "SIG", 3) == 0)
378 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000379 for (i = 0; i <= NSIG; i++)
380 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000381 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000382 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000383 }
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385}
386
387static int
388qual_fault(s, opt, not)
389 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000390 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000391 int not;
392{
393 return -1;
394}
395
396static int
397qual_desc(s, opt, not)
398 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000399 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000400 int not;
401{
Roland McGrath48a035f2006-01-12 09:45:56 +0000402 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000403 int desc = atoi(s);
404 if (desc < 0 || desc >= MAX_QUALS)
405 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000406 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000407 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000408 }
409 return -1;
410}
411
412static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000413lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000414 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415{
416 if (strcmp(s, "file") == 0)
417 return TRACE_FILE;
418 if (strcmp(s, "ipc") == 0)
419 return TRACE_IPC;
420 if (strcmp(s, "network") == 0)
421 return TRACE_NETWORK;
422 if (strcmp(s, "process") == 0)
423 return TRACE_PROCESS;
424 if (strcmp(s, "signal") == 0)
425 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000426 if (strcmp(s, "desc") == 0)
427 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000428 return -1;
429}
430
431void
432qualify(s)
433char *s;
434{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000435 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 int not;
437 char *p;
438 int i, n;
439
440 opt = &qual_options[0];
441 for (i = 0; (p = qual_options[i].option_name); i++) {
442 n = strlen(p);
443 if (strncmp(s, p, n) == 0 && s[n] == '=') {
444 opt = &qual_options[i];
445 s += n + 1;
446 break;
447 }
448 }
449 not = 0;
450 if (*s == '!') {
451 not = 1;
452 s++;
453 }
454 if (strcmp(s, "none") == 0) {
455 not = 1 - not;
456 s = "all";
457 }
458 if (strcmp(s, "all") == 0) {
459 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000460 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 }
462 return;
463 }
464 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000465 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 }
467 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
468 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
469 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000470 if (sysent0[i].sys_flags & n)
471 qualify_one(i, opt, not, 0);
472
473#if SUPPORTED_PERSONALITIES >= 2
474 if (sysent1[i].sys_flags & n)
475 qualify_one(i, opt, not, 1);
476#endif /* SUPPORTED_PERSONALITIES >= 2 */
477
478#if SUPPORTED_PERSONALITIES >= 3
479 if (sysent2[i].sys_flags & n)
480 qualify_one(i, opt, not, 2);
481#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000482 }
483 continue;
484 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000485 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000486 fprintf(stderr, "strace: invalid %s `%s'\n",
487 opt->argument_name, p);
488 exit(1);
489 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 }
491 return;
492}
493
494static void
495dumpio(tcp)
496struct tcb *tcp;
497{
498 if (syserror(tcp))
499 return;
500 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
501 return;
Roland McGrath17352792005-06-07 23:21:26 +0000502 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000504#ifdef SYS_pread64
505 case SYS_pread64:
506#endif
507#if defined SYS_pread && SYS_pread64 != SYS_pread
508 case SYS_pread:
509#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000510#ifdef SYS_recv
511 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000512#elif defined SYS_sub_recv
513 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#endif
515#ifdef SYS_recvfrom
516 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000517#elif defined SYS_sub_recvfrom
518 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519#endif
520 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
521 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
522 break;
523 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000524#ifdef SYS_pwrite64
525 case SYS_pwrite64:
526#endif
527#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
528 case SYS_pwrite:
529#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530#ifdef SYS_send
531 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000532#elif defined SYS_sub_send
533 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#endif
535#ifdef SYS_sendto
536 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000537#elif defined SYS_sub_sendto
538 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539#endif
540 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
541 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
542 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000543#ifdef SYS_readv
544 case SYS_readv:
545 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
546 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
547 break;
548#endif
549#ifdef SYS_writev
550 case SYS_writev:
551
552 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
553 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
554 break;
555#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000556 }
557}
558
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000560enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561#else /* FREEBSD */
562enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
563
564struct subcall {
565 int call;
566 int nsubcalls;
567 int subcalls[5];
568};
569
Roland McGratha4d48532005-06-08 20:45:28 +0000570static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000571 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000572#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000573 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000574#else
575 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
576#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000577 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
578};
579#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000581#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582
Roland McGratha4d48532005-06-08 20:45:28 +0000583static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000584 /* SYS_SOCKET */ 97,
585 /* SYS_BIND */ 104,
586 /* SYS_CONNECT */ 98,
587 /* SYS_LISTEN */ 106,
588 /* SYS_ACCEPT */ 99,
589 /* SYS_GETSOCKNAME */ 150,
590 /* SYS_GETPEERNAME */ 141,
591 /* SYS_SOCKETPAIR */ 135,
592 /* SYS_SEND */ 101,
593 /* SYS_RECV */ 102,
594 /* SYS_SENDTO */ 133,
595 /* SYS_RECVFROM */ 125,
596 /* SYS_SHUTDOWN */ 134,
597 /* SYS_SETSOCKOPT */ 105,
598 /* SYS_GETSOCKOPT */ 118,
599 /* SYS_SENDMSG */ 114,
600 /* SYS_RECVMSG */ 113
601};
602
Roland McGratha4d48532005-06-08 20:45:28 +0000603#if defined (SPARC) || defined (SPARC64)
604static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000605sparc_socket_decode (tcp)
606struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607{
608 volatile long addr;
609 volatile int i, n;
610
611 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
612 return;
613 }
614 tcp->scno = socket_map [tcp->u_arg [0]-1];
615 n = tcp->u_nargs = sysent [tcp->scno].nargs;
616 addr = tcp->u_arg [1];
617 for (i = 0; i < n; i++){
618 int arg;
619 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
620 arg = 0;
621 tcp->u_arg [i] = arg;
622 addr += sizeof (arg);
623 }
624}
Roland McGratha4d48532005-06-08 20:45:28 +0000625#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626
Roland McGratha4d48532005-06-08 20:45:28 +0000627static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628decode_subcall(tcp, subcall, nsubcalls, style)
629struct tcb *tcp;
630int subcall;
631int nsubcalls;
632enum subcall_style style;
633{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000634 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000635 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000636 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000637
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638 switch (style) {
639 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000640 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
641 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642 tcp->scno = subcall + tcp->u_arg[0];
643 if (sysent[tcp->scno].nargs != -1)
644 tcp->u_nargs = sysent[tcp->scno].nargs;
645 else
646 tcp->u_nargs--;
647 for (i = 0; i < tcp->u_nargs; i++)
648 tcp->u_arg[i] = tcp->u_arg[i + 1];
649 break;
650 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000651 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
652 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653 tcp->scno = subcall + tcp->u_arg[0];
654 addr = tcp->u_arg[1];
655 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000656 if (size == sizeof(int)) {
657 unsigned int arg;
658 if (umove(tcp, addr, &arg) < 0)
659 arg = 0;
660 tcp->u_arg[i] = arg;
661 }
662 else if (size == sizeof(long)) {
663 unsigned long arg;
664 if (umove(tcp, addr, &arg) < 0)
665 arg = 0;
666 tcp->u_arg[i] = arg;
667 }
668 else
669 abort();
670 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671 }
672 tcp->u_nargs = sysent[tcp->scno].nargs;
673 break;
674 case mask_style:
675 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676 for (i = 0; mask; i++)
677 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000678 if (i >= nsubcalls)
679 return;
680 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681 tcp->scno = subcall + i;
682 if (sysent[tcp->scno].nargs != -1)
683 tcp->u_nargs = sysent[tcp->scno].nargs;
684 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000685 case door_style:
686 /*
687 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000688 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000689 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000690 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
691 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000692 tcp->scno = subcall + tcp->u_arg[5];
693 if (sysent[tcp->scno].nargs != -1)
694 tcp->u_nargs = sysent[tcp->scno].nargs;
695 else
696 tcp->u_nargs--;
697 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000698#ifdef FREEBSD
699 case table_style:
700 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
701 if (subcalls_table[i].call == tcp->scno) break;
702 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
703 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
704 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
705 for (i = 0; i < tcp->u_nargs; i++)
706 tcp->u_arg[i] = tcp->u_arg[i + 1];
707 }
708 break;
709#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000710 }
711}
712#endif
713
714struct tcb *tcp_last = NULL;
715
716static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000717internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000718{
719 /*
720 * We must always trace a few critical system calls in order to
721 * correctly support following forks in the presence of tracing
722 * qualifiers.
723 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000724 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000726 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
727 return 0;
728
729 func = sysent[tcp->scno].sys_func;
730
731 if (sys_exit == func)
732 return internal_exit(tcp);
733
734 if ( sys_fork == func
735#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
736 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000737#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000738#if UNIXWARE > 2
739 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000741 )
742 return internal_fork(tcp);
743
744#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
745 if (sys_clone == func)
746 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000747#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000749 if ( sys_execve == func
750#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
751 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000753#if UNIXWARE > 2
754 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000755#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000756 )
757 return internal_exec(tcp);
758
759 if ( sys_waitpid == func
760 || sys_wait4 == func
761#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
762 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000763#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000764#ifdef ALPHA
765 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000766#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000767 )
768 return internal_wait(tcp, 2);
769
770#if defined(LINUX) || defined(SVR4)
771 if (sys_waitid == func)
772 return internal_wait(tcp, 3);
773#endif
774
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 return 0;
776}
777
Wichert Akkermanc7926982000-04-10 22:22:31 +0000778
779#ifdef LINUX
780#if defined (I386)
781 static long eax;
782#elif defined (IA64)
783 long r8, r10, psr;
784 long ia32 = 0;
785#elif defined (POWERPC)
786 static long result,flags;
787#elif defined (M68K)
788 static int d0;
789#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000790 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000791#elif defined (ALPHA)
792 static long r0;
793 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000794#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000795 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000796 static unsigned long trap;
797#elif defined(MIPS)
798 static long a3;
799 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000800#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000801 static long gpr2;
802 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000803 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000804#elif defined(HPPA)
805 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000806#elif defined(SH)
807 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000808#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000809 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000810#elif defined(X86_64)
811 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000812#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000813#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000814#ifdef FREEBSD
815 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000816#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000817
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000819get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820struct tcb *tcp;
821{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000822 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000823#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000824 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000825#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000827#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000828#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000829 if (tcp->flags & TCB_WAITEXECVE) {
830 /*
831 * When the execve system call completes successfully, the
832 * new process still has -ENOSYS (old style) or __NR_execve
833 * (new style) in gpr2. We cannot recover the scno again
834 * by disassembly, because the image that executed the
835 * syscall is gone now. Fortunately, we don't want it. We
836 * leave the flag set so that syscall_fixup can fake the
837 * result.
838 */
839 if (tcp->flags & TCB_INSYSCALL)
840 return 1;
841 /*
842 * This is the SIGTRAP after execve. We cannot try to read
843 * the system call here either.
844 */
845 tcp->flags &= ~TCB_WAITEXECVE;
846 return 0;
847 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000848
849 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
850 return -1;
851
852 if (syscall_mode != -ENOSYS) {
853 /*
854 * Since kernel version 2.5.44 the scno gets passed in gpr2.
855 */
856 scno = syscall_mode;
857 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000858 /*
859 * Old style of "passing" the scno via the SVC instruction.
860 */
861
862 long opcode, offset_reg, tmp;
863 void * svc_addr;
864 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
865 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
866 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
867 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000868
Michal Ludvig882eda82002-11-11 12:50:47 +0000869 if (upeek(pid, PT_PSWADDR, &pc) < 0)
870 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000871 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000872 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000873 if (errno) {
874 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000875 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000876 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000877
878 /*
879 * We have to check if the SVC got executed directly or via an
880 * EXECUTE instruction. In case of EXECUTE it is necessary to do
881 * instruction decoding to derive the system call number.
882 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
883 * so that this doesn't work if a SVC opcode is part of an EXECUTE
884 * opcode. Since there is no way to find out the opcode size this
885 * is the best we can do...
886 */
887
888 if ((opcode & 0xff00) == 0x0a00) {
889 /* SVC opcode */
890 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000891 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000892 else {
893 /* SVC got executed by EXECUTE instruction */
894
895 /*
896 * Do instruction decoding of EXECUTE. If you really want to
897 * understand this, read the Principles of Operations.
898 */
899 svc_addr = (void *) (opcode & 0xfff);
900
901 tmp = 0;
902 offset_reg = (opcode & 0x000f0000) >> 16;
903 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
904 return -1;
905 svc_addr += tmp;
906
907 tmp = 0;
908 offset_reg = (opcode & 0x0000f000) >> 12;
909 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
910 return -1;
911 svc_addr += tmp;
912
913 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
914 if (errno)
915 return -1;
916#if defined(S390X)
917 scno >>= 48;
918#else
919 scno >>= 16;
920#endif
921 tmp = 0;
922 offset_reg = (opcode & 0x00f00000) >> 20;
923 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
924 return -1;
925
926 scno = (scno | tmp) & 0xff;
927 }
928 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000929#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000930 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 return -1;
932 if (!(tcp->flags & TCB_INSYSCALL)) {
933 /* Check if we return from execve. */
934 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
935 tcp->flags &= ~TCB_WAITEXECVE;
936 return 0;
937 }
938 }
939#elif defined (I386)
940 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
941 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000942#elif defined (X86_64)
943 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
944 return -1;
945
Roland McGrath761b5d72002-12-15 23:58:31 +0000946 if (!(tcp->flags & TCB_INSYSCALL)) {
947 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 long val;
949
950 /* Check CS register value. On x86-64 linux it is:
951 * 0x33 for long mode (64 bit)
952 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 * to be cached.
955 */
956 if (upeek(pid, 8*CS, &val) < 0)
957 return -1;
958 switch(val)
959 {
960 case 0x23: currpers = 1; break;
961 case 0x33: currpers = 0; break;
962 default:
963 fprintf(stderr, "Unknown value CS=0x%02X while "
964 "detecting personality of process "
965 "PID=%d\n", (int)val, pid);
966 currpers = current_personality;
967 break;
968 }
969#if 0
970 /* This version analyzes the opcode of a syscall instruction.
971 * (int 0x80 on i386 vs. syscall on x86-64)
972 * It works, but is too complicated.
973 */
974 unsigned long val, rip, i;
975
976 if(upeek(pid, 8*RIP, &rip)<0)
977 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000978
Michal Ludvig0e035502002-09-23 15:41:01 +0000979 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
980 rip-=2;
981 errno = 0;
982
Roland McGrath761b5d72002-12-15 23:58:31 +0000983 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
984 if (errno)
985 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000986 strerror(errno));
987 switch (call & 0xffff)
988 {
989 /* x86-64: syscall = 0x0f 0x05 */
990 case 0x050f: currpers = 0; break;
991 /* i386: int 0x80 = 0xcd 0x80 */
992 case 0x80cd: currpers = 1; break;
993 default:
994 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000995 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000996 "Unknown syscall opcode (0x%04X) while "
997 "detecting personality of process "
998 "PID=%d\n", (int)call, pid);
999 break;
1000 }
1001#endif
1002 if(currpers != current_personality)
1003 {
1004 char *names[]={"64 bit", "32 bit"};
1005 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +00001006 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +00001007 pid, names[current_personality]);
1008 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001009 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001010#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001011# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001012 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001013 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001014 if (!(tcp->flags & TCB_INSYSCALL)) {
1015 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001016 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001017 return -1;
1018 } else {
1019 if (upeek (pid, PT_R15, &scno) < 0)
1020 return -1;
1021 }
Roland McGrathba954762003-03-05 06:29:06 +00001022 /* Check if we return from execve. */
1023 if (tcp->flags & TCB_WAITEXECVE) {
1024 tcp->flags &= ~TCB_WAITEXECVE;
1025 return 0;
1026 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001027 } else {
1028 /* syscall in progress */
1029 if (upeek (pid, PT_R8, &r8) < 0)
1030 return -1;
1031 if (upeek (pid, PT_R10, &r10) < 0)
1032 return -1;
1033 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001035 /*
1036 * Read complete register set in one go.
1037 */
1038 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1039 return -1;
1040
1041 /*
1042 * We only need to grab the syscall number on syscall entry.
1043 */
1044 if (regs.ARM_ip == 0) {
1045 /*
1046 * Note: we only deal with only 32-bit CPUs here.
1047 */
1048 if (regs.ARM_cpsr & 0x20) {
1049 /*
1050 * Get the Thumb-mode system call number
1051 */
1052 scno = regs.ARM_r7;
1053 } else {
1054 /*
1055 * Get the ARM-mode system call number
1056 */
1057 errno = 0;
1058 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1059 if (errno)
1060 return -1;
1061
1062 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1063 tcp->flags &= ~TCB_WAITEXECVE;
1064 return 0;
1065 }
1066
Roland McGrathf691bd22006-04-25 07:34:41 +00001067 /* Handle the EABI syscall convention. We do not
1068 bother converting structures between the two
1069 ABIs, but basic functionality should work even
1070 if strace and the traced program have different
1071 ABIs. */
1072 if (scno == 0xef000000) {
1073 scno = regs.ARM_r7;
1074 } else {
1075 if ((scno & 0x0ff00000) != 0x0f900000) {
1076 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1077 scno);
1078 return -1;
1079 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001080
Roland McGrathf691bd22006-04-25 07:34:41 +00001081 /*
1082 * Fixup the syscall number
1083 */
1084 scno &= 0x000fffff;
1085 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001086 }
1087
1088 if (tcp->flags & TCB_INSYSCALL) {
1089 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1090 tcp->flags &= ~TCB_INSYSCALL;
1091 }
1092 } else {
1093 if (!(tcp->flags & TCB_INSYSCALL)) {
1094 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1095 tcp->flags |= TCB_INSYSCALL;
1096 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097 }
1098#elif defined (M68K)
1099 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1100 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001101#elif defined (MIPS)
1102 if (upeek(pid, REG_A3, &a3) < 0)
1103 return -1;
1104
1105 if(!(tcp->flags & TCB_INSYSCALL)) {
1106 if (upeek(pid, REG_V0, &scno) < 0)
1107 return -1;
1108
1109 if (scno < 0 || scno > nsyscalls) {
1110 if(a3 == 0 || a3 == -1) {
1111 if(debug)
1112 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1113 return 0;
1114 }
1115 }
1116 } else {
1117 if (upeek(pid, REG_V0, &r2) < 0)
1118 return -1;
1119 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120#elif defined (ALPHA)
1121 if (upeek(pid, REG_A3, &a3) < 0)
1122 return -1;
1123
1124 if (!(tcp->flags & TCB_INSYSCALL)) {
1125 if (upeek(pid, REG_R0, &scno) < 0)
1126 return -1;
1127
1128 /* Check if we return from execve. */
1129 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1130 tcp->flags &= ~TCB_WAITEXECVE;
1131 return 0;
1132 }
1133
1134 /*
1135 * Do some sanity checks to figure out if it's
1136 * really a syscall entry
1137 */
1138 if (scno < 0 || scno > nsyscalls) {
1139 if (a3 == 0 || a3 == -1) {
1140 if (debug)
1141 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1142 return 0;
1143 }
1144 }
1145 }
1146 else {
1147 if (upeek(pid, REG_R0, &r0) < 0)
1148 return -1;
1149 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001150#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 /* Everything we need is in the current register set. */
1152 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1153 return -1;
1154
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 /* If we are entering, then disassemble the syscall trap. */
1156 if (!(tcp->flags & TCB_INSYSCALL)) {
1157 /* Retrieve the syscall trap instruction. */
1158 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001159 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001160#if defined(SPARC64)
1161 trap >>= 32;
1162#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 if (errno)
1164 return -1;
1165
1166 /* Disassemble the trap to see what personality to use. */
1167 switch (trap) {
1168 case 0x91d02010:
1169 /* Linux/SPARC syscall trap. */
1170 set_personality(0);
1171 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001172 case 0x91d0206d:
1173 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001174 set_personality(2);
1175 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 case 0x91d02000:
1177 /* SunOS syscall trap. (pers 1) */
1178 fprintf(stderr,"syscall: SunOS no support\n");
1179 return -1;
1180 case 0x91d02008:
1181 /* Solaris 2.x syscall trap. (per 2) */
1182 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001183 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 case 0x91d02009:
1185 /* NetBSD/FreeBSD syscall trap. */
1186 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1187 return -1;
1188 case 0x91d02027:
1189 /* Solaris 2.x gettimeofday */
1190 set_personality(1);
1191 break;
1192 default:
1193 /* Unknown syscall trap. */
1194 if(tcp->flags & TCB_WAITEXECVE) {
1195 tcp->flags &= ~TCB_WAITEXECVE;
1196 return 0;
1197 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001198#if defined (SPARC64)
1199 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1200#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001201 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001202#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 return -1;
1204 }
1205
1206 /* Extract the system call number from the registers. */
1207 if (trap == 0x91d02027)
1208 scno = 156;
1209 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001210 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001212 scno = regs.r_o0;
1213 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 }
1215 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001216#elif defined(HPPA)
1217 if (upeek(pid, PT_GR20, &scno) < 0)
1218 return -1;
1219 if (!(tcp->flags & TCB_INSYSCALL)) {
1220 /* Check if we return from execve. */
1221 if ((tcp->flags & TCB_WAITEXECVE)) {
1222 tcp->flags &= ~TCB_WAITEXECVE;
1223 return 0;
1224 }
1225 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001226#elif defined(SH)
1227 /*
1228 * In the new syscall ABI, the system call number is in R3.
1229 */
1230 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1231 return -1;
1232
1233 if (scno < 0) {
1234 /* Odd as it may seem, a glibc bug has been known to cause
1235 glibc to issue bogus negative syscall numbers. So for
1236 our purposes, make strace print what it *should* have been */
1237 long correct_scno = (scno & 0xff);
1238 if (debug)
1239 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001240 "Detected glibc bug: bogus system call number = %ld, "
1241 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001242 scno,
1243 correct_scno);
1244 scno = correct_scno;
1245 }
1246
1247
1248 if (!(tcp->flags & TCB_INSYSCALL)) {
1249 /* Check if we return from execve. */
1250 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1251 tcp->flags &= ~TCB_WAITEXECVE;
1252 return 0;
1253 }
1254 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001255#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001256 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1257 return -1;
1258 scno &= 0xFFFF;
1259
1260 if (!(tcp->flags & TCB_INSYSCALL)) {
1261 /* Check if we return from execve. */
1262 if (tcp->flags & TCB_WAITEXECVE) {
1263 tcp->flags &= ~TCB_WAITEXECVE;
1264 return 0;
1265 }
1266 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001267#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268#endif /* LINUX */
1269#ifdef SUNOS4
1270 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1271 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001272#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001273 /* new syscall ABI returns result in R0 */
1274 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1275 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001276#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001277 /* ABI defines result returned in r9 */
1278 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1279 return -1;
1280
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001281#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001282#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001284 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001286#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001287 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001288#else /* FREEBSD */
1289 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1290 perror("pread");
1291 return -1;
1292 }
1293 switch (regs.r_eax) {
1294 case SYS_syscall:
1295 case SYS___syscall:
1296 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1297 break;
1298 default:
1299 scno = regs.r_eax;
1300 break;
1301 }
1302#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001304#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001305 if (!(tcp->flags & TCB_INSYSCALL))
1306 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001307 return 1;
1308}
1309
Pavel Machek4dc3b142000-02-01 17:58:41 +00001310
Roland McGrath17352792005-06-07 23:21:26 +00001311long
1312known_scno(tcp)
1313struct tcb *tcp;
1314{
1315 long scno = tcp->scno;
1316 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1317 scno = sysent[scno].native_scno;
1318 else
1319 scno += NR_SYSCALL_BASE;
1320 return scno;
1321}
1322
Roland McGratha4d48532005-06-08 20:45:28 +00001323static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001324syscall_fixup(tcp)
1325struct tcb *tcp;
1326{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001327#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001328 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001329#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001330 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001331
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001333 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334 if (
1335 scno == SYS_fork
1336#ifdef SYS_vfork
1337 || scno == SYS_vfork
1338#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001339#ifdef SYS_fork1
1340 || scno == SYS_fork1
1341#endif /* SYS_fork1 */
1342#ifdef SYS_forkall
1343 || scno == SYS_forkall
1344#endif /* SYS_forkall */
1345#ifdef SYS_rfork1
1346 || scno == SYS_rfork1
1347#endif /* SYS_fork1 */
1348#ifdef SYS_rforkall
1349 || scno == SYS_rforkall
1350#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 ) {
1352 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001353 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001355 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001356 }
1357 else {
1358 fprintf(stderr, "syscall: missing entry\n");
1359 tcp->flags |= TCB_INSYSCALL;
1360 }
1361 }
1362 }
1363 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001364 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365 fprintf(stderr, "syscall: missing exit\n");
1366 tcp->flags &= ~TCB_INSYSCALL;
1367 }
1368 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001369#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370#ifdef SUNOS4
1371 if (!(tcp->flags & TCB_INSYSCALL)) {
1372 if (scno == 0) {
1373 fprintf(stderr, "syscall: missing entry\n");
1374 tcp->flags |= TCB_INSYSCALL;
1375 }
1376 }
1377 else {
1378 if (scno != 0) {
1379 if (debug) {
1380 /*
1381 * This happens when a signal handler
1382 * for a signal which interrupted a
1383 * a system call makes another system call.
1384 */
1385 fprintf(stderr, "syscall: missing exit\n");
1386 }
1387 tcp->flags &= ~TCB_INSYSCALL;
1388 }
1389 }
1390#endif /* SUNOS4 */
1391#ifdef LINUX
1392#if defined (I386)
1393 if (upeek(pid, 4*EAX, &eax) < 0)
1394 return -1;
1395 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1396 if (debug)
1397 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1398 return 0;
1399 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001400#elif defined (X86_64)
1401 if (upeek(pid, 8*RAX, &rax) < 0)
1402 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001403 if (current_personality == 1)
1404 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001405 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1406 if (debug)
1407 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1408 return 0;
1409 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001410#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001411 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1412 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001413 if (syscall_mode != -ENOSYS)
1414 syscall_mode = tcp->scno;
1415 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001416 if (debug)
1417 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1418 return 0;
1419 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001420 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1421 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1422 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1423 /*
1424 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1425 * flag set for the post-execve SIGTRAP to see and reset.
1426 */
1427 gpr2 = 0;
1428 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429#elif defined (POWERPC)
1430# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001431 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001433 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001434 return -1;
1435 if (flags & SO_MASK)
1436 result = -result;
1437#elif defined (M68K)
1438 if (upeek(pid, 4*PT_D0, &d0) < 0)
1439 return -1;
1440 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1441 if (debug)
1442 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1443 return 0;
1444 }
1445#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001446 /*
1447 * Nothing required
1448 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001449#elif defined (HPPA)
1450 if (upeek(pid, PT_GR28, &r28) < 0)
1451 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001452#elif defined(IA64)
1453 if (upeek(pid, PT_R10, &r10) < 0)
1454 return -1;
1455 if (upeek(pid, PT_R8, &r8) < 0)
1456 return -1;
1457 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1458 if (debug)
1459 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1460 return 0;
1461 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001462#endif
1463#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001464 return 1;
1465}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001466
Roland McGratha4d48532005-06-08 20:45:28 +00001467static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001468get_error(tcp)
1469struct tcb *tcp;
1470{
1471 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001473#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001474 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1475 tcp->u_rval = -1;
1476 u_error = -gpr2;
1477 }
1478 else {
1479 tcp->u_rval = gpr2;
1480 u_error = 0;
1481 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001482#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483#ifdef I386
1484 if (eax < 0 && -eax < nerrnos) {
1485 tcp->u_rval = -1;
1486 u_error = -eax;
1487 }
1488 else {
1489 tcp->u_rval = eax;
1490 u_error = 0;
1491 }
1492#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001493#ifdef X86_64
1494 if (rax < 0 && -rax < nerrnos) {
1495 tcp->u_rval = -1;
1496 u_error = -rax;
1497 }
1498 else {
1499 tcp->u_rval = rax;
1500 u_error = 0;
1501 }
1502#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001503#ifdef IA64
1504 if (ia32) {
1505 int err;
1506
1507 err = (int)r8;
1508 if (err < 0 && -err < nerrnos) {
1509 tcp->u_rval = -1;
1510 u_error = -err;
1511 }
1512 else {
1513 tcp->u_rval = err;
1514 u_error = 0;
1515 }
1516 } else {
1517 if (r10) {
1518 tcp->u_rval = -1;
1519 u_error = r8;
1520 } else {
1521 tcp->u_rval = r8;
1522 u_error = 0;
1523 }
1524 }
1525#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001526#ifdef MIPS
1527 if (a3) {
1528 tcp->u_rval = -1;
1529 u_error = r2;
1530 } else {
1531 tcp->u_rval = r2;
1532 u_error = 0;
1533 }
1534#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001536 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537 tcp->u_rval = -1;
1538 u_error = -result;
1539 }
1540 else {
1541 tcp->u_rval = result;
1542 u_error = 0;
1543 }
1544#else /* !POWERPC */
1545#ifdef M68K
1546 if (d0 && (unsigned) -d0 < nerrnos) {
1547 tcp->u_rval = -1;
1548 u_error = -d0;
1549 }
1550 else {
1551 tcp->u_rval = d0;
1552 u_error = 0;
1553 }
1554#else /* !M68K */
1555#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001556 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001558 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559 }
1560 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001561 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001562 u_error = 0;
1563 }
1564#else /* !ARM */
1565#ifdef ALPHA
1566 if (a3) {
1567 tcp->u_rval = -1;
1568 u_error = r0;
1569 }
1570 else {
1571 tcp->u_rval = r0;
1572 u_error = 0;
1573 }
1574#else /* !ALPHA */
1575#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001576 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001578 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579 }
1580 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001581 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 u_error = 0;
1583 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001584#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001585#ifdef SPARC64
1586 if (regs.r_tstate & 0x1100000000UL) {
1587 tcp->u_rval = -1;
1588 u_error = regs.r_o0;
1589 }
1590 else {
1591 tcp->u_rval = regs.r_o0;
1592 u_error = 0;
1593 }
1594#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001595#ifdef HPPA
1596 if (r28 && (unsigned) -r28 < nerrnos) {
1597 tcp->u_rval = -1;
1598 u_error = -r28;
1599 }
1600 else {
1601 tcp->u_rval = r28;
1602 u_error = 0;
1603 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001604#else
1605#ifdef SH
1606 /* interpret R0 as return value or error number */
1607 if (r0 && (unsigned) -r0 < nerrnos) {
1608 tcp->u_rval = -1;
1609 u_error = -r0;
1610 }
1611 else {
1612 tcp->u_rval = r0;
1613 u_error = 0;
1614 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001615#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001616#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001617 /* interpret result as return value or error number */
1618 if (r9 && (unsigned) -r9 < nerrnos) {
1619 tcp->u_rval = -1;
1620 u_error = -r9;
1621 }
1622 else {
1623 tcp->u_rval = r9;
1624 u_error = 0;
1625 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001626#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001627#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001628#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001630#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631#endif /* ALPHA */
1632#endif /* ARM */
1633#endif /* M68K */
1634#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001635#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001636#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001637#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001639#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640#endif /* LINUX */
1641#ifdef SUNOS4
1642 /* get error code from user struct */
1643 if (upeek(pid, uoff(u_error), &u_error) < 0)
1644 return -1;
1645 u_error >>= 24; /* u_error is a char */
1646
1647 /* get system call return value */
1648 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1649 return -1;
1650#endif /* SUNOS4 */
1651#ifdef SVR4
1652#ifdef SPARC
1653 /* Judicious guessing goes a long way. */
1654 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1655 tcp->u_rval = -1;
1656 u_error = tcp->status.pr_reg[R_O0];
1657 }
1658 else {
1659 tcp->u_rval = tcp->status.pr_reg[R_O0];
1660 u_error = 0;
1661 }
1662#endif /* SPARC */
1663#ifdef I386
1664 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001665 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001667 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 }
1669 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001670 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001671#ifdef HAVE_LONG_LONG
1672 tcp->u_lrval =
1673 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1674 tcp->status.PR_REG[EAX];
1675#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676 u_error = 0;
1677 }
1678#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001679#ifdef X86_64
1680 /* Wanna know how to kill an hour single-stepping? */
1681 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1682 tcp->u_rval = -1;
1683 u_error = tcp->status.PR_REG[RAX];
1684 }
1685 else {
1686 tcp->u_rval = tcp->status.PR_REG[RAX];
1687 u_error = 0;
1688 }
1689#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690#ifdef MIPS
1691 if (tcp->status.pr_reg[CTX_A3]) {
1692 tcp->u_rval = -1;
1693 u_error = tcp->status.pr_reg[CTX_V0];
1694 }
1695 else {
1696 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1697 u_error = 0;
1698 }
1699#endif /* MIPS */
1700#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001701#ifdef FREEBSD
1702 if (regs.r_eflags & PSL_C) {
1703 tcp->u_rval = -1;
1704 u_error = regs.r_eax;
1705 } else {
1706 tcp->u_rval = regs.r_eax;
1707 tcp->u_lrval =
1708 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1709 u_error = 0;
1710 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001711#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001712 tcp->u_error = u_error;
1713 return 1;
1714}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715
Roland McGrathb69f81b2002-12-21 23:25:18 +00001716int
1717force_result(tcp, error, rval)
1718 struct tcb *tcp;
1719 int error;
1720 long rval;
1721{
1722#ifdef LINUX
1723#if defined(S390) || defined(S390X)
1724 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001725 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1726 return -1;
1727#else /* !S390 && !S390X */
1728#ifdef I386
1729 eax = error ? -error : rval;
1730 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1731 return -1;
1732#else /* !I386 */
1733#ifdef X86_64
1734 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001735 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001736 return -1;
1737#else
1738#ifdef IA64
1739 if (ia32) {
1740 r8 = error ? -error : rval;
1741 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1742 return -1;
1743 }
1744 else {
1745 if (error) {
1746 r8 = error;
1747 r10 = -1;
1748 }
1749 else {
1750 r8 = rval;
1751 r10 = 0;
1752 }
1753 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1754 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1755 return -1;
1756 }
1757#else /* !IA64 */
1758#ifdef MIPS
1759 if (error) {
1760 r2 = error;
1761 a3 = -1;
1762 }
1763 else {
1764 r2 = rval;
1765 a3 = 0;
1766 }
1767 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1768 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1769 return -1;
1770#else
1771#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001772 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001773 return -1;
1774 if (error) {
1775 flags |= SO_MASK;
1776 result = error;
1777 }
1778 else {
1779 flags &= ~SO_MASK;
1780 result = rval;
1781 }
Roland McGratheb285352003-01-14 09:59:00 +00001782 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1783 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784 return -1;
1785#else /* !POWERPC */
1786#ifdef M68K
1787 d0 = error ? -error : rval;
1788 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1789 return -1;
1790#else /* !M68K */
1791#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001792 regs.ARM_r0 = error ? -error : rval;
1793 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 return -1;
1795#else /* !ARM */
1796#ifdef ALPHA
1797 if (error) {
1798 a3 = -1;
1799 r0 = error;
1800 }
1801 else {
1802 a3 = 0;
1803 r0 = rval;
1804 }
1805 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1806 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1807 return -1;
1808#else /* !ALPHA */
1809#ifdef SPARC
1810 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1811 return -1;
1812 if (error) {
1813 regs.r_psr |= PSR_C;
1814 regs.r_o0 = error;
1815 }
1816 else {
1817 regs.r_psr &= ~PSR_C;
1818 regs.r_o0 = rval;
1819 }
1820 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1821 return -1;
1822#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001823#ifdef SPARC64
1824 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1825 return -1;
1826 if (error) {
1827 regs.r_tstate |= 0x1100000000UL;
1828 regs.r_o0 = error;
1829 }
1830 else {
1831 regs.r_tstate &= ~0x1100000000UL;
1832 regs.r_o0 = rval;
1833 }
1834 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1835 return -1;
1836#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837#ifdef HPPA
1838 r28 = error ? -error : rval;
1839 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1840 return -1;
1841#else
1842#ifdef SH
1843 r0 = error ? -error : rval;
1844 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1845 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001846#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001847#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001848 r9 = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1850 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001851#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852#endif /* SH */
1853#endif /* HPPA */
1854#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001855#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001856#endif /* ALPHA */
1857#endif /* ARM */
1858#endif /* M68K */
1859#endif /* POWERPC */
1860#endif /* MIPS */
1861#endif /* IA64 */
1862#endif /* X86_64 */
1863#endif /* I386 */
1864#endif /* S390 || S390X */
1865#endif /* LINUX */
1866#ifdef SUNOS4
1867 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1868 error << 24) < 0 ||
1869 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1870 return -1;
1871#endif /* SUNOS4 */
1872#ifdef SVR4
1873 /* XXX no clue */
1874 return -1;
1875#endif /* SVR4 */
1876#ifdef FREEBSD
1877 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1878 perror("pread");
1879 return -1;
1880 }
1881 if (error) {
1882 regs.r_eflags |= PSL_C;
1883 regs.r_eax = error;
1884 }
1885 else {
1886 regs.r_eflags &= ~PSL_C;
1887 regs.r_eax = rval;
1888 }
1889 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1890 perror("pwrite");
1891 return -1;
1892 }
1893#endif /* FREEBSD */
1894
1895 /* All branches reach here on success (only). */
1896 tcp->u_error = error;
1897 tcp->u_rval = rval;
1898 return 0;
1899}
1900
Roland McGratha4d48532005-06-08 20:45:28 +00001901static int
1902syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001903struct tcb *tcp;
1904{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001905#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001906 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001907#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001909#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001910 {
1911 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001912 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1913 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001914 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001915 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001916 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001917 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001918 return -1;
1919 }
1920 }
1921#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001922 {
1923 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001924 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1925 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001926 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001927 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001928 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001929 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1930 * for scno somewhere above here!
1931 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001932 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1933 return -1;
1934 }
1935 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001936#elif defined (IA64)
1937 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001938 if (!ia32) {
1939 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1940 /* be backwards compatible with kernel < 2.4.4... */
1941# ifndef PT_RBS_END
1942# define PT_RBS_END PT_AR_BSP
1943# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001944
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001945 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001946 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001947 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1948 return -1;
1949
1950 sof = (cfm >> 0) & 0x7f;
1951 sol = (cfm >> 7) & 0x7f;
1952 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1953
1954 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1955 && sysent[tcp->scno].nargs != -1)
1956 tcp->u_nargs = sysent[tcp->scno].nargs;
1957 else
1958 tcp->u_nargs = MAX_ARGS;
1959 for (i = 0; i < tcp->u_nargs; ++i) {
1960 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1961 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1962 return -1;
1963 }
1964 } else {
1965 int i;
1966
1967 if (/* EBX = out0 */
1968 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1969 /* ECX = out1 */
1970 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1971 /* EDX = out2 */
1972 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1973 /* ESI = out3 */
1974 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1975 /* EDI = out4 */
1976 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1977 /* EBP = out5 */
1978 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1979 return -1;
1980
1981 for (i = 0; i < 6; ++i)
1982 /* truncate away IVE sign-extension */
1983 tcp->u_arg[i] &= 0xffffffff;
1984
1985 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1986 && sysent[tcp->scno].nargs != -1)
1987 tcp->u_nargs = sysent[tcp->scno].nargs;
1988 else
1989 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001990 }
1991 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001992#elif defined (MIPS)
1993 {
1994 long sp;
1995 int i, nargs;
1996
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001997 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1998 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001999 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002000 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002001 if(nargs > 4) {
2002 if(upeek(pid, REG_SP, &sp) < 0)
2003 return -1;
2004 for(i = 0; i < 4; i++) {
2005 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2006 return -1;
2007 }
2008 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2009 (char *)(tcp->u_arg + 4));
2010 } else {
2011 for(i = 0; i < nargs; i++) {
2012 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2013 return -1;
2014 }
2015 }
2016 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002018#ifndef PT_ORIG_R3
2019#define PT_ORIG_R3 34
2020#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002021 {
2022 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002023 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2024 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002025 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002026 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002027 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002028 if (upeek(pid, (i==0) ?
2029 (sizeof(unsigned long)*PT_ORIG_R3) :
2030 ((i+PT_R3)*sizeof(unsigned long)),
2031 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002032 return -1;
2033 }
2034 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002035#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002036 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002037 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002038
2039 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2040 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002041 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002042 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002043 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002044 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002045 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002046#elif defined (HPPA)
2047 {
2048 int i;
2049
2050 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2051 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002052 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002053 tcp->u_nargs = MAX_ARGS;
2054 for (i = 0; i < tcp->u_nargs; i++) {
2055 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2056 return -1;
2057 }
2058 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002059#elif defined(ARM)
2060 {
2061 int i;
2062
2063 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2064 tcp->u_nargs = sysent[tcp->scno].nargs;
2065 else
2066 tcp->u_nargs = MAX_ARGS;
2067 for (i = 0; i < tcp->u_nargs; i++)
2068 tcp->u_arg[i] = regs.uregs[i];
2069 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002070#elif defined(SH)
2071 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002072 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002073 static int syscall_regs[] = {
2074 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2075 REG_REG0, REG_REG0+1, REG_REG0+2
2076 };
2077
2078 tcp->u_nargs = sysent[tcp->scno].nargs;
2079 for (i = 0; i < tcp->u_nargs; i++) {
2080 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2081 return -1;
2082 }
2083 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002084#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002085 {
2086 int i;
2087 /* Registers used by SH5 Linux system calls for parameters */
2088 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2089
2090 /*
2091 * TODO: should also check that the number of arguments encoded
2092 * in the trap number matches the number strace expects.
2093 */
2094 /*
2095 assert(sysent[tcp->scno].nargs <
2096 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2097 */
2098
2099 tcp->u_nargs = sysent[tcp->scno].nargs;
2100 for (i = 0; i < tcp->u_nargs; i++) {
2101 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2102 return -1;
2103 }
2104 }
2105
Michal Ludvig0e035502002-09-23 15:41:01 +00002106#elif defined(X86_64)
2107 {
2108 int i;
2109 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2110 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002111 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002112 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002113
Michal Ludvig0e035502002-09-23 15:41:01 +00002114 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2115 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002116 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002117 tcp->u_nargs = MAX_ARGS;
2118 for (i = 0; i < tcp->u_nargs; i++) {
2119 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2120 return -1;
2121 }
2122 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002123#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 {
2125 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002126 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2127 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002128 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002129 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130 for (i = 0; i < tcp->u_nargs; i++) {
2131 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2132 return -1;
2133 }
2134 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002135#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136#endif /* LINUX */
2137#ifdef SUNOS4
2138 {
2139 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002140 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2141 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002142 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002143 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144 for (i = 0; i < tcp->u_nargs; i++) {
2145 struct user *u;
2146
2147 if (upeek(pid, uoff(u_arg[0]) +
2148 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2149 return -1;
2150 }
2151 }
2152#endif /* SUNOS4 */
2153#ifdef SVR4
2154#ifdef MIPS
2155 /*
2156 * SGI is broken: even though it has pr_sysarg, it doesn't
2157 * set them on system call entry. Get a clue.
2158 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002159 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002160 tcp->u_nargs = sysent[tcp->scno].nargs;
2161 else
2162 tcp->u_nargs = tcp->status.pr_nsysarg;
2163 if (tcp->u_nargs > 4) {
2164 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2165 4*sizeof(tcp->u_arg[0]));
2166 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2167 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2168 }
2169 else {
2170 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2171 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2172 }
John Hughes25299712001-03-06 10:10:06 +00002173#elif UNIXWARE >= 2
2174 /*
2175 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2176 */
2177 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2178 tcp->u_nargs = sysent[tcp->scno].nargs;
2179 else
2180 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2181 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2182 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2183#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002184 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002185 tcp->u_nargs = sysent[tcp->scno].nargs;
2186 else
2187 tcp->u_nargs = tcp->status.pr_nsysarg;
2188 {
2189 int i;
2190 for (i = 0; i < tcp->u_nargs; i++)
2191 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2192 }
John Hughes25299712001-03-06 10:10:06 +00002193#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002194 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002195 tcp->u_nargs = sysent[tcp->scno].nargs;
2196 else
2197 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002198 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002199 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002200#else
2201 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002202#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002203#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002204#ifdef FREEBSD
2205 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2206 sysent[tcp->scno].nargs > tcp->status.val)
2207 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002208 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209 tcp->u_nargs = tcp->status.val;
2210 if (tcp->u_nargs < 0)
2211 tcp->u_nargs = 0;
2212 if (tcp->u_nargs > MAX_ARGS)
2213 tcp->u_nargs = MAX_ARGS;
2214 switch(regs.r_eax) {
2215 case SYS___syscall:
2216 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2217 regs.r_esp + sizeof(int) + sizeof(quad_t));
2218 break;
2219 case SYS_syscall:
2220 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2221 regs.r_esp + 2 * sizeof(int));
2222 break;
2223 default:
2224 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2225 regs.r_esp + sizeof(int));
2226 break;
2227 }
2228#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002229 return 1;
2230}
2231
2232int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002233trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002234{
2235 int sys_res;
2236 struct timeval tv;
2237 int res;
2238
2239 /* Measure the exit time as early as possible to avoid errors. */
2240 if (dtime && (tcp->flags & TCB_INSYSCALL))
2241 gettimeofday(&tv, NULL);
2242
2243 res = get_scno(tcp);
2244 if (res != 1)
2245 return res;
2246
2247 res = syscall_fixup(tcp);
2248 if (res != 1)
2249 return res;
2250
2251 if (tcp->flags & TCB_INSYSCALL) {
2252 long u_error;
2253 res = get_error(tcp);
2254 if (res != 1)
2255 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002256
2257 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002258 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2259 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002260 tcp->flags &= ~TCB_INSYSCALL;
2261 return 0;
2262 }
2263
2264 if (tcp->flags & TCB_REPRINT) {
2265 printleader(tcp);
2266 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002268 tprintf("syscall_%lu", tcp->scno);
2269 else
2270 tprintf("%s", sysent[tcp->scno].sys_name);
2271 tprintf(" resumed> ");
2272 }
2273
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002274 if (cflag)
2275 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002276
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002277 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002278 || (qual_flags[tcp->scno] & QUAL_RAW))
2279 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002280 else {
2281 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002282 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002283 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002284 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002285 u_error = tcp->u_error;
2286 tprintf(") ");
2287 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002288 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2289 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002290 if (u_error)
2291 tprintf("= -1 (errno %ld)", u_error);
2292 else
2293 tprintf("= %#lx", tcp->u_rval);
2294 }
2295 else if (!(sys_res & RVAL_NONE) && u_error) {
2296 switch (u_error) {
2297#ifdef LINUX
2298 case ERESTARTSYS:
2299 tprintf("= ? ERESTARTSYS (To be restarted)");
2300 break;
2301 case ERESTARTNOINTR:
2302 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2303 break;
2304 case ERESTARTNOHAND:
2305 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2306 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002307 case ERESTART_RESTARTBLOCK:
2308 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2309 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002310#endif /* LINUX */
2311 default:
2312 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002313 if (u_error < 0)
2314 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002315 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002316 tprintf("%s (%s)", errnoent[u_error],
2317 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002318 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002319 tprintf("ERRNO_%ld (%s)", u_error,
2320 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321 break;
2322 }
2323 }
2324 else {
2325 if (sys_res & RVAL_NONE)
2326 tprintf("= ?");
2327 else {
2328 switch (sys_res & RVAL_MASK) {
2329 case RVAL_HEX:
2330 tprintf("= %#lx", tcp->u_rval);
2331 break;
2332 case RVAL_OCTAL:
2333 tprintf("= %#lo", tcp->u_rval);
2334 break;
2335 case RVAL_UDECIMAL:
2336 tprintf("= %lu", tcp->u_rval);
2337 break;
2338 case RVAL_DECIMAL:
2339 tprintf("= %ld", tcp->u_rval);
2340 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002341#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002342 case RVAL_LHEX:
2343 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002344 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002345 case RVAL_LOCTAL:
2346 tprintf("= %#llo", tcp->u_lrval);
2347 break;
2348 case RVAL_LUDECIMAL:
2349 tprintf("= %llu", tcp->u_lrval);
2350 break;
2351 case RVAL_LDECIMAL:
2352 tprintf("= %lld", tcp->u_lrval);
2353 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002354#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002355 default:
2356 fprintf(stderr,
2357 "invalid rval format\n");
2358 break;
2359 }
2360 }
2361 if ((sys_res & RVAL_STR) && tcp->auxstr)
2362 tprintf(" (%s)", tcp->auxstr);
2363 }
2364 if (dtime) {
2365 tv_sub(&tv, &tv, &tcp->etime);
2366 tprintf(" <%ld.%06ld>",
2367 (long) tv.tv_sec, (long) tv.tv_usec);
2368 }
2369 printtrailer(tcp);
2370
2371 dumpio(tcp);
2372 if (fflush(tcp->outf) == EOF)
2373 return -1;
2374 tcp->flags &= ~TCB_INSYSCALL;
2375 return 0;
2376 }
2377
2378 /* Entering system call */
2379 res = syscall_enter(tcp);
2380 if (res != 1)
2381 return res;
2382
Roland McGrath17352792005-06-07 23:21:26 +00002383 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002384#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002385#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002386 case SYS_socketcall:
2387 decode_subcall(tcp, SYS_socket_subcall,
2388 SYS_socket_nsubcalls, deref_style);
2389 break;
2390 case SYS_ipc:
2391 decode_subcall(tcp, SYS_ipc_subcall,
2392 SYS_ipc_nsubcalls, shift_style);
2393 break;
Roland McGrath17352792005-06-07 23:21:26 +00002394#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002395#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002396 case SYS_socketcall:
2397 sparc_socket_decode (tcp);
2398 break;
2399#endif
2400#endif /* LINUX */
2401#ifdef SVR4
2402#ifdef SYS_pgrpsys_subcall
2403 case SYS_pgrpsys:
2404 decode_subcall(tcp, SYS_pgrpsys_subcall,
2405 SYS_pgrpsys_nsubcalls, shift_style);
2406 break;
2407#endif /* SYS_pgrpsys_subcall */
2408#ifdef SYS_sigcall_subcall
2409 case SYS_sigcall:
2410 decode_subcall(tcp, SYS_sigcall_subcall,
2411 SYS_sigcall_nsubcalls, mask_style);
2412 break;
2413#endif /* SYS_sigcall_subcall */
2414 case SYS_msgsys:
2415 decode_subcall(tcp, SYS_msgsys_subcall,
2416 SYS_msgsys_nsubcalls, shift_style);
2417 break;
2418 case SYS_shmsys:
2419 decode_subcall(tcp, SYS_shmsys_subcall,
2420 SYS_shmsys_nsubcalls, shift_style);
2421 break;
2422 case SYS_semsys:
2423 decode_subcall(tcp, SYS_semsys_subcall,
2424 SYS_semsys_nsubcalls, shift_style);
2425 break;
2426#if 0 /* broken */
2427 case SYS_utssys:
2428 decode_subcall(tcp, SYS_utssys_subcall,
2429 SYS_utssys_nsubcalls, shift_style);
2430 break;
2431#endif
2432 case SYS_sysfs:
2433 decode_subcall(tcp, SYS_sysfs_subcall,
2434 SYS_sysfs_nsubcalls, shift_style);
2435 break;
2436 case SYS_spcall:
2437 decode_subcall(tcp, SYS_spcall_subcall,
2438 SYS_spcall_nsubcalls, shift_style);
2439 break;
2440#ifdef SYS_context_subcall
2441 case SYS_context:
2442 decode_subcall(tcp, SYS_context_subcall,
2443 SYS_context_nsubcalls, shift_style);
2444 break;
2445#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002446#ifdef SYS_door_subcall
2447 case SYS_door:
2448 decode_subcall(tcp, SYS_door_subcall,
2449 SYS_door_nsubcalls, door_style);
2450 break;
2451#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002452#ifdef SYS_kaio_subcall
2453 case SYS_kaio:
2454 decode_subcall(tcp, SYS_kaio_subcall,
2455 SYS_kaio_nsubcalls, shift_style);
2456 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002457#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002458#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002459#ifdef FREEBSD
2460 case SYS_msgsys:
2461 case SYS_shmsys:
2462 case SYS_semsys:
2463 decode_subcall(tcp, 0, 0, table_style);
2464 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002465#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002466#ifdef SUNOS4
2467 case SYS_semsys:
2468 decode_subcall(tcp, SYS_semsys_subcall,
2469 SYS_semsys_nsubcalls, shift_style);
2470 break;
2471 case SYS_msgsys:
2472 decode_subcall(tcp, SYS_msgsys_subcall,
2473 SYS_msgsys_nsubcalls, shift_style);
2474 break;
2475 case SYS_shmsys:
2476 decode_subcall(tcp, SYS_shmsys_subcall,
2477 SYS_shmsys_nsubcalls, shift_style);
2478 break;
2479#endif
2480 }
2481
2482 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002483 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002484 tcp->flags |= TCB_INSYSCALL;
2485 return 0;
2486 }
2487
2488 if (cflag) {
2489 gettimeofday(&tcp->etime, NULL);
2490 tcp->flags |= TCB_INSYSCALL;
2491 return 0;
2492 }
2493
2494 printleader(tcp);
2495 tcp->flags &= ~TCB_REPRINT;
2496 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002497 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002498 tprintf("syscall_%lu(", tcp->scno);
2499 else
2500 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002501 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2503 sys_res = printargs(tcp);
2504 else
2505 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2506 if (fflush(tcp->outf) == EOF)
2507 return -1;
2508 tcp->flags |= TCB_INSYSCALL;
2509 /* Measure the entrance time as late as possible to avoid errors. */
2510 if (dtime)
2511 gettimeofday(&tcp->etime, NULL);
2512 return sys_res;
2513}
2514
2515int
2516printargs(tcp)
2517struct tcb *tcp;
2518{
2519 if (entering(tcp)) {
2520 int i;
2521
2522 for (i = 0; i < tcp->u_nargs; i++)
2523 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2524 }
2525 return 0;
2526}
2527
2528long
2529getrval2(tcp)
2530struct tcb *tcp;
2531{
2532 long val = -1;
2533
2534#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002535#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002536 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2538 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002539 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002540#elif defined(SH)
2541 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2542 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002543#elif defined(IA64)
2544 if (upeek(tcp->pid, PT_R9, &val) < 0)
2545 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002546#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002547#endif /* LINUX */
2548
2549#ifdef SUNOS4
2550 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2551 return -1;
2552#endif /* SUNOS4 */
2553
2554#ifdef SVR4
2555#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002556 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002557#endif /* SPARC */
2558#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002559 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002560#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002561#ifdef X86_64
2562 val = tcp->status.PR_REG[RDX];
2563#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002564#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002565 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566#endif /* MIPS */
2567#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002568#ifdef FREEBSD
2569 struct reg regs;
2570 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2571 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002572#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002573 return val;
2574}
2575
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002576#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577/*
2578 * Apparently, indirect system calls have already be converted by ptrace(2),
2579 * so if you see "indir" this program has gone astray.
2580 */
2581int
2582sys_indir(tcp)
2583struct tcb *tcp;
2584{
2585 int i, scno, nargs;
2586
2587 if (entering(tcp)) {
2588 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2589 fprintf(stderr, "Bogus syscall: %u\n", scno);
2590 return 0;
2591 }
2592 nargs = sysent[scno].nargs;
2593 tprintf("%s", sysent[scno].sys_name);
2594 for (i = 0; i < nargs; i++)
2595 tprintf(", %#lx", tcp->u_arg[i+1]);
2596 }
2597 return 0;
2598}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002599#endif /* SUNOS4 */