blob: 3f551cd4fadf65b10deb456605da67a6acfff75d [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#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#include <sys/reg.h>
47#ifndef PTRACE_PEEKUSR
48# define PTRACE_PEEKUSR PTRACE_PEEKUSER
49#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000050#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070051#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000052# ifdef HAVE_STRUCT_IA64_FPREG
53# define ia64_fpreg XXX_ia64_fpreg
54# endif
55# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
56# define pt_all_user_regs XXX_pt_all_user_regs
57# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070058#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000059# undef ia64_fpreg
60# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000061#endif
62
Roland McGrath6d1a65c2004-07-12 07:44:08 +000063#if defined (LINUX) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000064# undef PTRACE_GETREGS
65# define PTRACE_GETREGS PTRACE_GETREGS64
66# undef PTRACE_SETREGS
67# define PTRACE_SETREGS PTRACE_SETREGS64
68#endif /* LINUX && SPARC64 */
69
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000070#if defined(LINUX) && defined(IA64)
71# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Pavel Machekd8ae7e32000-02-01 17:17:25 +000075#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#ifdef LINUX
77#ifndef ERESTARTSYS
78#define ERESTARTSYS 512
79#endif
80#ifndef ERESTARTNOINTR
81#define ERESTARTNOINTR 513
82#endif
83#ifndef ERESTARTNOHAND
84#define ERESTARTNOHAND 514 /* restart if no handler.. */
85#endif
86#ifndef ENOIOCTLCMD
87#define ENOIOCTLCMD 515 /* No ioctl command */
88#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000089#ifndef ERESTART_RESTARTBLOCK
90#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
91#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifndef NSIG
93#define NSIG 32
94#endif
95#ifdef ARM
96#undef NSIG
97#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +000098#undef NR_SYSCALL_BASE
99#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100#endif
101#endif /* LINUX */
102
103#include "syscall.h"
104
105/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000106#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#define TF TRACE_FILE
108#define TI TRACE_IPC
109#define TN TRACE_NETWORK
110#define TP TRACE_PROCESS
111#define TS TRACE_SIGNAL
112
Roland McGrathee36ce12004-09-04 03:53:10 +0000113static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000114#include "syscallent.h"
115};
Roland McGrathee36ce12004-09-04 03:53:10 +0000116static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000117int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118
119#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000120static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121#include "syscallent1.h"
122};
Roland McGrathee36ce12004-09-04 03:53:10 +0000123static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000124int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125#endif /* SUPPORTED_PERSONALITIES >= 2 */
126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133#endif /* SUPPORTED_PERSONALITIES >= 3 */
134
Roland McGrathee36ce12004-09-04 03:53:10 +0000135const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000136int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137int nsyscalls;
138
139/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000140#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#undef TF
142#undef TI
143#undef TN
144#undef TP
145#undef TS
146
Roland McGrathee36ce12004-09-04 03:53:10 +0000147static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#include "errnoent.h"
149};
Roland McGrathee36ce12004-09-04 03:53:10 +0000150static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000151
152#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent1.h"
155};
Roland McGrathee36ce12004-09-04 03:53:10 +0000156static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157#endif /* SUPPORTED_PERSONALITIES >= 2 */
158
159#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000160static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161#include "errnoent2.h"
162};
Roland McGrathee36ce12004-09-04 03:53:10 +0000163static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164#endif /* SUPPORTED_PERSONALITIES >= 3 */
165
Roland McGrathee36ce12004-09-04 03:53:10 +0000166const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167int nerrnos;
168
169int current_personality;
170
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000171#ifndef PERSONALITY0_WORDSIZE
172# define PERSONALITY0_WORDSIZE sizeof(long)
173#endif
174const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
175 PERSONALITY0_WORDSIZE,
176#if SUPPORTED_PERSONALITIES > 1
177 PERSONALITY1_WORDSIZE,
178#endif
179#if SUPPORTED_PERSONALITIES > 2
180 PERSONALITY2_WORDSIZE,
181#endif
182};;
183
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000185set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000186{
187 switch (personality) {
188 case 0:
189 errnoent = errnoent0;
190 nerrnos = nerrnos0;
191 sysent = sysent0;
192 nsyscalls = nsyscalls0;
193 ioctlent = ioctlent0;
194 nioctlents = nioctlents0;
195 signalent = signalent0;
196 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000197 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198 break;
199
200#if SUPPORTED_PERSONALITIES >= 2
201 case 1:
202 errnoent = errnoent1;
203 nerrnos = nerrnos1;
204 sysent = sysent1;
205 nsyscalls = nsyscalls1;
206 ioctlent = ioctlent1;
207 nioctlents = nioctlents1;
208 signalent = signalent1;
209 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000210 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000211 break;
212#endif /* SUPPORTED_PERSONALITIES >= 2 */
213
214#if SUPPORTED_PERSONALITIES >= 3
215 case 2:
216 errnoent = errnoent2;
217 nerrnos = nerrnos2;
218 sysent = sysent2;
219 nsyscalls = nsyscalls2;
220 ioctlent = ioctlent2;
221 nioctlents = nioctlents2;
222 signalent = signalent2;
223 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000224 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000225 break;
226#endif /* SUPPORTED_PERSONALITIES >= 3 */
227
228 default:
229 return -1;
230 }
231
232 current_personality = personality;
233 return 0;
234}
235
Roland McGrathe10e62a2004-09-04 04:20:43 +0000236
Roland McGrath9797ceb2002-12-30 10:23:00 +0000237static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
Roland McGrathe10e62a2004-09-04 04:20:43 +0000239static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 int bitflag;
241 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000242 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000243 char *argument_name;
244} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000245 { QUAL_TRACE, "trace", qual_syscall, "system call" },
246 { QUAL_TRACE, "t", qual_syscall, "system call" },
247 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
248 { QUAL_ABBREV, "a", qual_syscall, "system call" },
249 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
250 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
251 { QUAL_RAW, "raw", qual_syscall, "system call" },
252 { QUAL_RAW, "x", qual_syscall, "system call" },
253 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
254 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
255 { QUAL_SIGNAL, "s", qual_signal, "signal" },
256 { QUAL_FAULT, "fault", qual_fault, "fault" },
257 { QUAL_FAULT, "faults", qual_fault, "fault" },
258 { QUAL_FAULT, "m", qual_fault, "fault" },
259 { QUAL_READ, "read", qual_desc, "descriptor" },
260 { QUAL_READ, "reads", qual_desc, "descriptor" },
261 { QUAL_READ, "r", qual_desc, "descriptor" },
262 { QUAL_WRITE, "write", qual_desc, "descriptor" },
263 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
264 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265 { 0, NULL, NULL, NULL },
266};
267
Roland McGrath9797ceb2002-12-30 10:23:00 +0000268static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000269qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000270 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000271 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000272 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000273 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274{
Roland McGrath138c6a32006-01-12 09:50:49 +0000275 if (pers == 0 || pers < 0) {
276 if (not)
277 qual_flags0[n] &= ~opt->bitflag;
278 else
279 qual_flags0[n] |= opt->bitflag;
280 }
281
282#if SUPPORTED_PERSONALITIES >= 2
283 if (pers == 1 || pers < 0) {
284 if (not)
285 qual_flags1[n] &= ~opt->bitflag;
286 else
287 qual_flags1[n] |= opt->bitflag;
288 }
289#endif /* SUPPORTED_PERSONALITIES >= 2 */
290
291#if SUPPORTED_PERSONALITIES >= 3
292 if (pers == 2 || pers < 0) {
293 if (not)
294 qual_flags2[n] &= ~opt->bitflag;
295 else
296 qual_flags2[n] |= opt->bitflag;
297 }
298#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299}
300
301static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000302qual_syscall(s, opt, not)
303 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000304 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000305 int not;
306{
307 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000308 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000309
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000310 if (isdigit((unsigned char)*s)) {
311 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000312 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000313 return -1;
314 qualify_one(i, opt, not, -1);
315 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000316 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000317 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000318 if (strcmp(s, sysent0[i].sys_name) == 0) {
319 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000320 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000321 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000322
323#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000324 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000325 if (strcmp(s, sysent1[i].sys_name) == 0) {
326 qualify_one(i, opt, not, 1);
327 rc = 0;
328 }
329#endif /* SUPPORTED_PERSONALITIES >= 2 */
330
331#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent2[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 2);
335 rc = 0;
336 }
337#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000338
Roland McGrathfe6b3522005-02-02 04:40:11 +0000339 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000340}
341
342static int
343qual_signal(s, opt, not)
344 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000345 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000346 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347{
348 int i;
349 char buf[32];
350
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000351 if (isdigit((unsigned char)*s)) {
352 int signo = atoi(s);
353 if (signo < 0 || signo >= MAX_QUALS)
354 return -1;
355 qualify_one(signo, opt, not, -1);
356 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000357 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000358 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000359 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000360 strcpy(buf, s);
361 s = buf;
362 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000363 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364 if (strncmp(s, "SIG", 3) == 0)
365 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000366 for (i = 0; i <= NSIG; i++)
367 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000369 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000370 }
Roland McGrath76421df2005-02-02 03:51:18 +0000371 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372}
373
374static int
375qual_fault(s, opt, not)
376 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000377 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000378 int not;
379{
380 return -1;
381}
382
383static int
384qual_desc(s, opt, not)
385 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000386 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387 int not;
388{
Roland McGrath48a035f2006-01-12 09:45:56 +0000389 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000390 int desc = atoi(s);
391 if (desc < 0 || desc >= MAX_QUALS)
392 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000393 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000394 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395 }
396 return -1;
397}
398
399static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000401 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000402{
403 if (strcmp(s, "file") == 0)
404 return TRACE_FILE;
405 if (strcmp(s, "ipc") == 0)
406 return TRACE_IPC;
407 if (strcmp(s, "network") == 0)
408 return TRACE_NETWORK;
409 if (strcmp(s, "process") == 0)
410 return TRACE_PROCESS;
411 if (strcmp(s, "signal") == 0)
412 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000413 if (strcmp(s, "desc") == 0)
414 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415 return -1;
416}
417
418void
419qualify(s)
420char *s;
421{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000422 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423 int not;
424 char *p;
425 int i, n;
426
427 opt = &qual_options[0];
428 for (i = 0; (p = qual_options[i].option_name); i++) {
429 n = strlen(p);
430 if (strncmp(s, p, n) == 0 && s[n] == '=') {
431 opt = &qual_options[i];
432 s += n + 1;
433 break;
434 }
435 }
436 not = 0;
437 if (*s == '!') {
438 not = 1;
439 s++;
440 }
441 if (strcmp(s, "none") == 0) {
442 not = 1 - not;
443 s = "all";
444 }
445 if (strcmp(s, "all") == 0) {
446 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000447 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000448 }
449 return;
450 }
451 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000452 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000453 }
454 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
455 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000456 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000457 if (sysent0[i].sys_flags & n)
458 qualify_one(i, opt, not, 0);
459
460#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000461 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 if (sysent1[i].sys_flags & n)
463 qualify_one(i, opt, not, 1);
464#endif /* SUPPORTED_PERSONALITIES >= 2 */
465
466#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000467 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000468 if (sysent2[i].sys_flags & n)
469 qualify_one(i, opt, not, 2);
470#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 continue;
473 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000474 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000475 fprintf(stderr, "strace: invalid %s `%s'\n",
476 opt->argument_name, p);
477 exit(1);
478 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 }
480 return;
481}
482
483static void
484dumpio(tcp)
485struct tcb *tcp;
486{
487 if (syserror(tcp))
488 return;
489 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
490 return;
Roland McGrath17352792005-06-07 23:21:26 +0000491 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000493#ifdef SYS_pread64
494 case SYS_pread64:
495#endif
496#if defined SYS_pread && SYS_pread64 != SYS_pread
497 case SYS_pread:
498#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499#ifdef SYS_recv
500 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000501#elif defined SYS_sub_recv
502 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503#endif
504#ifdef SYS_recvfrom
505 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000506#elif defined SYS_sub_recvfrom
507 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000508#endif
509 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
510 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
511 break;
512 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000513#ifdef SYS_pwrite64
514 case SYS_pwrite64:
515#endif
516#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
517 case SYS_pwrite:
518#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519#ifdef SYS_send
520 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_send
522 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524#ifdef SYS_sendto
525 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000526#elif defined SYS_sub_sendto
527 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528#endif
529 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
530 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
531 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000532#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000533 case SYS_readv:
534 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
535 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
536 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000537#endif
538#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000539 case SYS_writev:
540 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
541 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
542 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000543#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 }
545}
546
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000548enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000549#else /* FREEBSD */
550enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
551
552struct subcall {
553 int call;
554 int nsubcalls;
555 int subcalls[5];
556};
557
Roland McGratha4d48532005-06-08 20:45:28 +0000558static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000560#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000562#else
563 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
564#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
566};
567#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000569#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570
Roland McGratha4d48532005-06-08 20:45:28 +0000571static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572decode_subcall(tcp, subcall, nsubcalls, style)
573struct tcb *tcp;
574int subcall;
575int nsubcalls;
576enum subcall_style style;
577{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000578 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000579 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000580 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 switch (style) {
583 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000584 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
585 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 tcp->scno = subcall + tcp->u_arg[0];
587 if (sysent[tcp->scno].nargs != -1)
588 tcp->u_nargs = sysent[tcp->scno].nargs;
589 else
590 tcp->u_nargs--;
591 for (i = 0; i < tcp->u_nargs; i++)
592 tcp->u_arg[i] = tcp->u_arg[i + 1];
593 break;
594 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000595 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
596 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 tcp->scno = subcall + tcp->u_arg[0];
598 addr = tcp->u_arg[1];
599 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000600 if (size == sizeof(int)) {
601 unsigned int arg;
602 if (umove(tcp, addr, &arg) < 0)
603 arg = 0;
604 tcp->u_arg[i] = arg;
605 }
606 else if (size == sizeof(long)) {
607 unsigned long arg;
608 if (umove(tcp, addr, &arg) < 0)
609 arg = 0;
610 tcp->u_arg[i] = arg;
611 }
612 else
613 abort();
614 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 }
616 tcp->u_nargs = sysent[tcp->scno].nargs;
617 break;
618 case mask_style:
619 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 for (i = 0; mask; i++)
621 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 if (i >= nsubcalls)
623 return;
624 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 tcp->scno = subcall + i;
626 if (sysent[tcp->scno].nargs != -1)
627 tcp->u_nargs = sysent[tcp->scno].nargs;
628 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000629 case door_style:
630 /*
631 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000632 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000633 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000634 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
635 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000636 tcp->scno = subcall + tcp->u_arg[5];
637 if (sysent[tcp->scno].nargs != -1)
638 tcp->u_nargs = sysent[tcp->scno].nargs;
639 else
640 tcp->u_nargs--;
641 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000642#ifdef FREEBSD
643 case table_style:
644 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
645 if (subcalls_table[i].call == tcp->scno) break;
646 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
647 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
648 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
649 for (i = 0; i < tcp->u_nargs; i++)
650 tcp->u_arg[i] = tcp->u_arg[i + 1];
651 }
652 break;
653#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654 }
655}
656#endif
657
658struct tcb *tcp_last = NULL;
659
660static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000661internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000662{
663 /*
664 * We must always trace a few critical system calls in order to
665 * correctly support following forks in the presence of tracing
666 * qualifiers.
667 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000668 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000670 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
671 return 0;
672
673 func = sysent[tcp->scno].sys_func;
674
675 if (sys_exit == func)
676 return internal_exit(tcp);
677
678 if ( sys_fork == func
679#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
680 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000682#if UNIXWARE > 2
683 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685 )
686 return internal_fork(tcp);
687
688#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
689 if (sys_clone == func)
690 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000691#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000693 if ( sys_execve == func
694#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
695 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000697#if UNIXWARE > 2
698 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000699#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000700 )
701 return internal_exec(tcp);
702
703 if ( sys_waitpid == func
704 || sys_wait4 == func
705#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
706 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000707#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000708#ifdef ALPHA
709 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000710#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000711 )
712 return internal_wait(tcp, 2);
713
714#if defined(LINUX) || defined(SVR4)
715 if (sys_waitid == func)
716 return internal_wait(tcp, 3);
717#endif
718
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 return 0;
720}
721
Wichert Akkermanc7926982000-04-10 22:22:31 +0000722
723#ifdef LINUX
724#if defined (I386)
725 static long eax;
726#elif defined (IA64)
727 long r8, r10, psr;
728 long ia32 = 0;
729#elif defined (POWERPC)
730 static long result,flags;
731#elif defined (M68K)
732 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000733#elif defined(BFIN)
734 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000736 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000737#elif defined (ALPHA)
738 static long r0;
739 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000740#elif defined(AVR32)
741 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000742#elif defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -0400743 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000744 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000745#elif defined(LINUX_MIPSN32)
746 static long long a3;
747 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000748#elif defined(MIPS)
749 static long a3;
750 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000751#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000752 static long gpr2;
753 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000754 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000755#elif defined(HPPA)
756 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000757#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000758 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000759#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000760 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000761#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000762 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000763#elif defined(CRISV10) || defined(CRISV32)
764 static long r10;
Roland McGrath761b5d72002-12-15 23:58:31 +0000765#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000766#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000767#ifdef FREEBSD
768 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000769#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000770
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000771int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000772get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000777# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000778 if (tcp->flags & TCB_WAITEXECVE) {
779 /*
780 * When the execve system call completes successfully, the
781 * new process still has -ENOSYS (old style) or __NR_execve
782 * (new style) in gpr2. We cannot recover the scno again
783 * by disassembly, because the image that executed the
784 * syscall is gone now. Fortunately, we don't want it. We
785 * leave the flag set so that syscall_fixup can fake the
786 * result.
787 */
788 if (tcp->flags & TCB_INSYSCALL)
789 return 1;
790 /*
791 * This is the SIGTRAP after execve. We cannot try to read
792 * the system call here either.
793 */
794 tcp->flags &= ~TCB_WAITEXECVE;
795 return 0;
796 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000797
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000798 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000799 return -1;
800
801 if (syscall_mode != -ENOSYS) {
802 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000803 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000804 */
805 scno = syscall_mode;
806 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000807 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 * Old style of "passing" the scno via the SVC instruction.
809 */
810
811 long opcode, offset_reg, tmp;
812 void * svc_addr;
813 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
814 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
815 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
816 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000817
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000818 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000819 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000820 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000821 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000822 if (errno) {
823 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000825 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000826
827 /*
828 * We have to check if the SVC got executed directly or via an
829 * EXECUTE instruction. In case of EXECUTE it is necessary to do
830 * instruction decoding to derive the system call number.
831 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
832 * so that this doesn't work if a SVC opcode is part of an EXECUTE
833 * opcode. Since there is no way to find out the opcode size this
834 * is the best we can do...
835 */
836
837 if ((opcode & 0xff00) == 0x0a00) {
838 /* SVC opcode */
839 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000840 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000841 else {
842 /* SVC got executed by EXECUTE instruction */
843
844 /*
845 * Do instruction decoding of EXECUTE. If you really want to
846 * understand this, read the Principles of Operations.
847 */
848 svc_addr = (void *) (opcode & 0xfff);
849
850 tmp = 0;
851 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000852 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 return -1;
854 svc_addr += tmp;
855
856 tmp = 0;
857 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000858 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000859 return -1;
860 svc_addr += tmp;
861
Denys Vlasenkofb036672009-01-23 16:30:26 +0000862 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000863 if (errno)
864 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000865# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000866 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000867# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000869# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000870 tmp = 0;
871 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000872 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000873 return -1;
874
875 scno = (scno | tmp) & 0xff;
876 }
877 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000878# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000879 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880 return -1;
881 if (!(tcp->flags & TCB_INSYSCALL)) {
882 /* Check if we return from execve. */
883 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
884 tcp->flags &= ~TCB_WAITEXECVE;
885 return 0;
886 }
887 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000888# elif defined(AVR32)
889 /*
890 * Read complete register set in one go.
891 */
892 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
893 return -1;
894
895 /*
896 * We only need to grab the syscall number on syscall entry.
897 */
898 if (!(tcp->flags & TCB_INSYSCALL)) {
899 scno = regs.r8;
900
901 /* Check if we return from execve. */
902 if (tcp->flags & TCB_WAITEXECVE) {
903 tcp->flags &= ~TCB_WAITEXECVE;
904 return 0;
905 }
906 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000907# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000908 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000909 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000910# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000911 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000913# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000914 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000915 return -1;
916
Roland McGrath761b5d72002-12-15 23:58:31 +0000917 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000918 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000919 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000920 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000921
922 /* Check CS register value. On x86-64 linux it is:
923 * 0x33 for long mode (64 bit)
924 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000925 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000926 * to be cached.
927 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000928 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000930 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000931 case 0x23: currpers = 1; break;
932 case 0x33: currpers = 0; break;
933 default:
934 fprintf(stderr, "Unknown value CS=0x%02X while "
935 "detecting personality of process "
936 "PID=%d\n", (int)val, pid);
937 currpers = current_personality;
938 break;
939 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000940# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000941 /* This version analyzes the opcode of a syscall instruction.
942 * (int 0x80 on i386 vs. syscall on x86-64)
943 * It works, but is too complicated.
944 */
945 unsigned long val, rip, i;
946
Denys Vlasenko8236f252009-01-02 18:10:08 +0000947 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000949
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000951 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 errno = 0;
953
Denys Vlasenko8236f252009-01-02 18:10:08 +0000954 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000955 if (errno)
956 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000958 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000959 /* x86-64: syscall = 0x0f 0x05 */
960 case 0x050f: currpers = 0; break;
961 /* i386: int 0x80 = 0xcd 0x80 */
962 case 0x80cd: currpers = 1; break;
963 default:
964 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000965 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000966 "Unknown syscall opcode (0x%04X) while "
967 "detecting personality of process "
968 "PID=%d\n", (int)call, pid);
969 break;
970 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000971# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000972 if (currpers != current_personality) {
973 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000975 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000976 pid, names[current_personality]);
977 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000978 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000979# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000980# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700981 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000982 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000983 if (!(tcp->flags & TCB_INSYSCALL)) {
984 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000985 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000986 return -1;
987 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700988 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000989 return -1;
990 }
Roland McGrathba954762003-03-05 06:29:06 +0000991 /* Check if we return from execve. */
992 if (tcp->flags & TCB_WAITEXECVE) {
993 tcp->flags &= ~TCB_WAITEXECVE;
994 return 0;
995 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000996 } else {
997 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001000 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001001 return -1;
1002 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001003# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001004 /*
1005 * Read complete register set in one go.
1006 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001007 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001008 return -1;
1009
1010 /*
1011 * We only need to grab the syscall number on syscall entry.
1012 */
1013 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001014 if (!(tcp->flags & TCB_INSYSCALL)) {
1015 /* Check if we return from execve. */
1016 if (tcp->flags & TCB_WAITEXECVE) {
1017 tcp->flags &= ~TCB_WAITEXECVE;
1018 return 0;
1019 }
1020 }
1021
Roland McGrath0f87c492003-06-03 23:29:04 +00001022 /*
1023 * Note: we only deal with only 32-bit CPUs here.
1024 */
1025 if (regs.ARM_cpsr & 0x20) {
1026 /*
1027 * Get the Thumb-mode system call number
1028 */
1029 scno = regs.ARM_r7;
1030 } else {
1031 /*
1032 * Get the ARM-mode system call number
1033 */
1034 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001035 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001036 if (errno)
1037 return -1;
1038
1039 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1040 tcp->flags &= ~TCB_WAITEXECVE;
1041 return 0;
1042 }
1043
Roland McGrathf691bd22006-04-25 07:34:41 +00001044 /* Handle the EABI syscall convention. We do not
1045 bother converting structures between the two
1046 ABIs, but basic functionality should work even
1047 if strace and the traced program have different
1048 ABIs. */
1049 if (scno == 0xef000000) {
1050 scno = regs.ARM_r7;
1051 } else {
1052 if ((scno & 0x0ff00000) != 0x0f900000) {
1053 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1054 scno);
1055 return -1;
1056 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001057
Roland McGrathf691bd22006-04-25 07:34:41 +00001058 /*
1059 * Fixup the syscall number
1060 */
1061 scno &= 0x000fffff;
1062 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001063 }
Roland McGrath56703312008-05-20 01:35:55 +00001064 if (scno & 0x0f0000) {
1065 /*
1066 * Handle ARM specific syscall
1067 */
1068 set_personality(1);
1069 scno &= 0x0000ffff;
1070 } else
1071 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001072
1073 if (tcp->flags & TCB_INSYSCALL) {
1074 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1075 tcp->flags &= ~TCB_INSYSCALL;
1076 }
1077 } else {
1078 if (!(tcp->flags & TCB_INSYSCALL)) {
1079 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1080 tcp->flags |= TCB_INSYSCALL;
1081 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001083# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001084 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001086# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001087 unsigned long long regs[38];
1088
Roland McGratheb9e2e82009-06-02 16:49:22 -07001089 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001090 return -1;
1091 a3 = regs[REG_A3];
1092 r2 = regs[REG_V0];
1093
1094 if(!(tcp->flags & TCB_INSYSCALL)) {
1095 scno = r2;
1096
1097 /* Check if we return from execve. */
1098 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1099 tcp->flags &= ~TCB_WAITEXECVE;
1100 return 0;
1101 }
1102
1103 if (scno < 0 || scno > nsyscalls) {
1104 if(a3 == 0 || a3 == -1) {
1105 if(debug)
1106 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1107 return 0;
1108 }
1109 }
1110 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001111# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001112 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001113 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001114 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001115 if (upeek(tcp, REG_V0, &scno) < 0)
1116 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001117
Roland McGrath542c2c62008-05-20 01:11:56 +00001118 /* Check if we return from execve. */
1119 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1120 tcp->flags &= ~TCB_WAITEXECVE;
1121 return 0;
1122 }
1123
Wichert Akkermanf90da011999-10-31 21:15:38 +00001124 if (scno < 0 || scno > nsyscalls) {
1125 if(a3 == 0 || a3 == -1) {
1126 if(debug)
1127 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1128 return 0;
1129 }
1130 }
1131 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001132 if (upeek(tcp, REG_V0, &r2) < 0)
1133 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001134 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001135# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001136 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 return -1;
1138
1139 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001140 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 return -1;
1142
1143 /* Check if we return from execve. */
1144 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1145 tcp->flags &= ~TCB_WAITEXECVE;
1146 return 0;
1147 }
1148
1149 /*
1150 * Do some sanity checks to figure out if it's
1151 * really a syscall entry
1152 */
1153 if (scno < 0 || scno > nsyscalls) {
1154 if (a3 == 0 || a3 == -1) {
1155 if (debug)
1156 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1157 return 0;
1158 }
1159 }
1160 }
1161 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001162 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 return -1;
1164 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001165# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001167 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 return -1;
1169
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001170 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 if (!(tcp->flags & TCB_INSYSCALL)) {
1172 /* Retrieve the syscall trap instruction. */
1173 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001175 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001176 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001177# else
1178 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001179# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180 if (errno)
1181 return -1;
1182
1183 /* Disassemble the trap to see what personality to use. */
1184 switch (trap) {
1185 case 0x91d02010:
1186 /* Linux/SPARC syscall trap. */
1187 set_personality(0);
1188 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001189 case 0x91d0206d:
1190 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001191 set_personality(2);
1192 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 case 0x91d02000:
1194 /* SunOS syscall trap. (pers 1) */
1195 fprintf(stderr,"syscall: SunOS no support\n");
1196 return -1;
1197 case 0x91d02008:
1198 /* Solaris 2.x syscall trap. (per 2) */
1199 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001200 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201 case 0x91d02009:
1202 /* NetBSD/FreeBSD syscall trap. */
1203 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1204 return -1;
1205 case 0x91d02027:
1206 /* Solaris 2.x gettimeofday */
1207 set_personality(1);
1208 break;
1209 default:
1210 /* Unknown syscall trap. */
1211 if(tcp->flags & TCB_WAITEXECVE) {
1212 tcp->flags &= ~TCB_WAITEXECVE;
1213 return 0;
1214 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001215# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001216 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001218 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001219# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220 return -1;
1221 }
1222
1223 /* Extract the system call number from the registers. */
1224 if (trap == 0x91d02027)
1225 scno = 156;
1226 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001227 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001229 scno = regs.u_regs[U_REG_O0];
1230 memmove (&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 }
1232 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001233# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001234 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001235 return -1;
1236 if (!(tcp->flags & TCB_INSYSCALL)) {
1237 /* Check if we return from execve. */
1238 if ((tcp->flags & TCB_WAITEXECVE)) {
1239 tcp->flags &= ~TCB_WAITEXECVE;
1240 return 0;
1241 }
1242 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001243# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001244 /*
1245 * In the new syscall ABI, the system call number is in R3.
1246 */
1247 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1248 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001249
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001250 if (scno < 0) {
1251 /* Odd as it may seem, a glibc bug has been known to cause
1252 glibc to issue bogus negative syscall numbers. So for
1253 our purposes, make strace print what it *should* have been */
1254 long correct_scno = (scno & 0xff);
1255 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001256 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001257 "Detected glibc bug: bogus system call"
1258 " number = %ld, correcting to %ld\n",
1259 scno,
1260 correct_scno);
1261 scno = correct_scno;
1262 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001263
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001264 if (!(tcp->flags & TCB_INSYSCALL)) {
1265 /* Check if we return from execve. */
1266 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1267 tcp->flags &= ~TCB_WAITEXECVE;
1268 return 0;
1269 }
1270 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001271# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001272 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001273 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001274 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001275
1276 if (!(tcp->flags & TCB_INSYSCALL)) {
1277 /* Check if we return from execve. */
1278 if (tcp->flags & TCB_WAITEXECVE) {
1279 tcp->flags &= ~TCB_WAITEXECVE;
1280 return 0;
1281 }
1282 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001283# elif defined(CRISV10) || defined(CRISV32)
1284 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1285 return -1;
1286# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001288
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001290 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001292#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001293 /* new syscall ABI returns result in R0 */
1294 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1295 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001296#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001297 /* ABI defines result returned in r9 */
1298 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1299 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001301
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001302#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001303# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001304 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001305# else
1306# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001307 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001308# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001309 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001310 perror("pread");
1311 return -1;
1312 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313 switch (regs.r_eax) {
1314 case SYS_syscall:
1315 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001316 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1317 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001318 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001319 scno = regs.r_eax;
1320 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001322# endif /* FREEBSD */
1323# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001324#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001325
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001326 if (!(tcp->flags & TCB_INSYSCALL))
1327 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001328 return 1;
1329}
1330
Pavel Machek4dc3b142000-02-01 17:58:41 +00001331
Roland McGrath17352792005-06-07 23:21:26 +00001332long
1333known_scno(tcp)
1334struct tcb *tcp;
1335{
1336 long scno = tcp->scno;
1337 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1338 scno = sysent[scno].native_scno;
1339 else
1340 scno += NR_SYSCALL_BASE;
1341 return scno;
1342}
1343
Roland McGratheb9e2e82009-06-02 16:49:22 -07001344/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001345 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001346 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1347 * 1: ok, continue in trace_syscall().
1348 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001349 * ("????" etc) and bail out.
1350 */
Roland McGratha4d48532005-06-08 20:45:28 +00001351static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001352syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001353{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001354#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001355 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001356
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001358 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 if (
1360 scno == SYS_fork
1361#ifdef SYS_vfork
1362 || scno == SYS_vfork
1363#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001364#ifdef SYS_fork1
1365 || scno == SYS_fork1
1366#endif /* SYS_fork1 */
1367#ifdef SYS_forkall
1368 || scno == SYS_forkall
1369#endif /* SYS_forkall */
1370#ifdef SYS_rfork1
1371 || scno == SYS_rfork1
1372#endif /* SYS_fork1 */
1373#ifdef SYS_rforkall
1374 || scno == SYS_rforkall
1375#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 ) {
1377 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001378 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001380 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381 }
1382 else {
1383 fprintf(stderr, "syscall: missing entry\n");
1384 tcp->flags |= TCB_INSYSCALL;
1385 }
1386 }
1387 }
1388 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001389 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 fprintf(stderr, "syscall: missing exit\n");
1391 tcp->flags &= ~TCB_INSYSCALL;
1392 }
1393 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001394#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395#ifdef SUNOS4
1396 if (!(tcp->flags & TCB_INSYSCALL)) {
1397 if (scno == 0) {
1398 fprintf(stderr, "syscall: missing entry\n");
1399 tcp->flags |= TCB_INSYSCALL;
1400 }
1401 }
1402 else {
1403 if (scno != 0) {
1404 if (debug) {
1405 /*
1406 * This happens when a signal handler
1407 * for a signal which interrupted a
1408 * a system call makes another system call.
1409 */
1410 fprintf(stderr, "syscall: missing exit\n");
1411 }
1412 tcp->flags &= ~TCB_INSYSCALL;
1413 }
1414 }
1415#endif /* SUNOS4 */
1416#ifdef LINUX
1417#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001418 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419 return -1;
1420 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1421 if (debug)
1422 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1423 return 0;
1424 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001425#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001426 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001427 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001428 if (current_personality == 1)
1429 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001430 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1431 if (debug)
1432 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1433 return 0;
1434 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001435#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001437 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001438 if (syscall_mode != -ENOSYS)
1439 syscall_mode = tcp->scno;
1440 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001441 if (debug)
1442 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1443 return 0;
1444 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001445 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1446 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1447 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1448 /*
1449 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1450 * flag set for the post-execve SIGTRAP to see and reset.
1451 */
1452 gpr2 = 0;
1453 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454#elif defined (POWERPC)
1455# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001457 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001458 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001459 return -1;
1460 if (flags & SO_MASK)
1461 result = -result;
1462#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464 return -1;
1465 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1466 if (debug)
1467 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1468 return 0;
1469 }
1470#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001471 /*
1472 * Nothing required
1473 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001474#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001475 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001476 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001477#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001478 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001479 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001480#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001481 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001482 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001483 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001484 return -1;
1485 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1486 if (debug)
1487 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1488 return 0;
1489 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001490#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001491 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001492 return -1;
1493 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1494 if (debug)
1495 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1496 return 0;
1497 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498#endif
1499#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001500 return 1;
1501}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001502
Roland McGrathc1e45922008-05-27 23:18:29 +00001503#ifdef LINUX
1504/*
1505 * Check the syscall return value register value for whether it is
1506 * a negated errno code indicating an error, or a success return value.
1507 */
1508static inline int
1509is_negated_errno(unsigned long int val)
1510{
1511 unsigned long int max = -(long int) nerrnos;
1512 if (personality_wordsize[current_personality] < sizeof(val)) {
1513 val = (unsigned int) val;
1514 max = (unsigned int) max;
1515 }
1516 return val > max;
1517}
1518#endif
1519
Roland McGratha4d48532005-06-08 20:45:28 +00001520static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001521get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001522{
1523 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001525# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001526 if (is_negated_errno(gpr2)) {
1527 tcp->u_rval = -1;
1528 u_error = -gpr2;
1529 }
1530 else {
1531 tcp->u_rval = gpr2;
1532 u_error = 0;
1533 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001534# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001535 if (is_negated_errno(eax)) {
1536 tcp->u_rval = -1;
1537 u_error = -eax;
1538 }
1539 else {
1540 tcp->u_rval = eax;
1541 u_error = 0;
1542 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001543# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 if (is_negated_errno(rax)) {
1545 tcp->u_rval = -1;
1546 u_error = -rax;
1547 }
1548 else {
1549 tcp->u_rval = rax;
1550 u_error = 0;
1551 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001552# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001553 if (ia32) {
1554 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001555
Roland McGrathc1e45922008-05-27 23:18:29 +00001556 err = (int)r8;
1557 if (is_negated_errno(err)) {
1558 tcp->u_rval = -1;
1559 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001560 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001561 else {
1562 tcp->u_rval = err;
1563 u_error = 0;
1564 }
1565 } else {
1566 if (r10) {
1567 tcp->u_rval = -1;
1568 u_error = r8;
1569 } else {
1570 tcp->u_rval = r8;
1571 u_error = 0;
1572 }
1573 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001574# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001575 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001576 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001577 u_error = r2;
1578 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001579 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001580 u_error = 0;
1581 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001582# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001583 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584 tcp->u_rval = -1;
1585 u_error = -result;
1586 }
1587 else {
1588 tcp->u_rval = result;
1589 u_error = 0;
1590 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001591# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001592 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593 tcp->u_rval = -1;
1594 u_error = -d0;
1595 }
1596 else {
1597 tcp->u_rval = d0;
1598 u_error = 0;
1599 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001600# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001601 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001603 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 }
1605 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001606 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 u_error = 0;
1608 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001609# elif defined(AVR32)
1610 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1611 tcp->u_rval = -1;
1612 u_error = -regs.r12;
1613 }
1614 else {
1615 tcp->u_rval = regs.r12;
1616 u_error = 0;
1617 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001618# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001619 if (is_negated_errno(r0)) {
1620 tcp->u_rval = -1;
1621 u_error = -r0;
1622 } else {
1623 tcp->u_rval = r0;
1624 u_error = 0;
1625 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001626# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 if (a3) {
1628 tcp->u_rval = -1;
1629 u_error = r0;
1630 }
1631 else {
1632 tcp->u_rval = r0;
1633 u_error = 0;
1634 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001635# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001636 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001638 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 }
1640 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001641 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 u_error = 0;
1643 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001644# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001645 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001646 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001647 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001648 }
1649 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001650 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001651 u_error = 0;
1652 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001653# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001654 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001655 tcp->u_rval = -1;
1656 u_error = -r28;
1657 }
1658 else {
1659 tcp->u_rval = r28;
1660 u_error = 0;
1661 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001662# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001663 /* interpret R0 as return value or error number */
1664 if (is_negated_errno(r0)) {
1665 tcp->u_rval = -1;
1666 u_error = -r0;
1667 }
1668 else {
1669 tcp->u_rval = r0;
1670 u_error = 0;
1671 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001672# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001673 /* interpret result as return value or error number */
1674 if (is_negated_errno(r9)) {
1675 tcp->u_rval = -1;
1676 u_error = -r9;
1677 }
1678 else {
1679 tcp->u_rval = r9;
1680 u_error = 0;
1681 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001682# elif defined(CRISV10) || defined(CRISV32)
1683 if (r10 && (unsigned) -r10 < nerrnos) {
1684 tcp->u_rval = -1;
1685 u_error = -r10;
1686 }
1687 else {
1688 tcp->u_rval = r10;
1689 u_error = 0;
1690 }
1691# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692#endif /* LINUX */
1693#ifdef SUNOS4
1694 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001695 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696 return -1;
1697 u_error >>= 24; /* u_error is a char */
1698
1699 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001700 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001701 return -1;
1702#endif /* SUNOS4 */
1703#ifdef SVR4
1704#ifdef SPARC
1705 /* Judicious guessing goes a long way. */
1706 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1707 tcp->u_rval = -1;
1708 u_error = tcp->status.pr_reg[R_O0];
1709 }
1710 else {
1711 tcp->u_rval = tcp->status.pr_reg[R_O0];
1712 u_error = 0;
1713 }
1714#endif /* SPARC */
1715#ifdef I386
1716 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001717 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001719 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 }
1721 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001722 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001723#ifdef HAVE_LONG_LONG
1724 tcp->u_lrval =
1725 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1726 tcp->status.PR_REG[EAX];
1727#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 u_error = 0;
1729 }
1730#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001731#ifdef X86_64
1732 /* Wanna know how to kill an hour single-stepping? */
1733 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1734 tcp->u_rval = -1;
1735 u_error = tcp->status.PR_REG[RAX];
1736 }
1737 else {
1738 tcp->u_rval = tcp->status.PR_REG[RAX];
1739 u_error = 0;
1740 }
1741#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742#ifdef MIPS
1743 if (tcp->status.pr_reg[CTX_A3]) {
1744 tcp->u_rval = -1;
1745 u_error = tcp->status.pr_reg[CTX_V0];
1746 }
1747 else {
1748 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1749 u_error = 0;
1750 }
1751#endif /* MIPS */
1752#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001753#ifdef FREEBSD
1754 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001755 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001756 u_error = regs.r_eax;
1757 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001758 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001759 tcp->u_lrval =
1760 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1761 u_error = 0;
1762 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001763#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001764 tcp->u_error = u_error;
1765 return 1;
1766}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767
Roland McGrathb69f81b2002-12-21 23:25:18 +00001768int
1769force_result(tcp, error, rval)
1770 struct tcb *tcp;
1771 int error;
1772 long rval;
1773{
1774#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001775# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001776 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001777 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1778 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001779# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001780 eax = error ? -error : rval;
1781 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1782 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001783# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001785 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001787# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001788 if (ia32) {
1789 r8 = error ? -error : rval;
1790 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1791 return -1;
1792 }
1793 else {
1794 if (error) {
1795 r8 = error;
1796 r10 = -1;
1797 }
1798 else {
1799 r8 = rval;
1800 r10 = 0;
1801 }
1802 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1803 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1804 return -1;
1805 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001806# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001807 r0 = error ? -error : rval;
1808 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1809 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001810# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001811 if (error) {
1812 r2 = error;
1813 a3 = -1;
1814 }
1815 else {
1816 r2 = rval;
1817 a3 = 0;
1818 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001819 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001820 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1821 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001822 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001823# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001824 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001825 return -1;
1826 if (error) {
1827 flags |= SO_MASK;
1828 result = error;
1829 }
1830 else {
1831 flags &= ~SO_MASK;
1832 result = rval;
1833 }
Roland McGratheb285352003-01-14 09:59:00 +00001834 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1835 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001837# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 d0 = error ? -error : rval;
1839 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1840 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001841# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001842 regs.ARM_r0 = error ? -error : rval;
1843 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001845# elif defined(AVR32)
1846 regs.r12 = error ? -error : rval;
1847 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1848 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001849# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001850 if (error) {
1851 a3 = -1;
1852 r0 = error;
1853 }
1854 else {
1855 a3 = 0;
1856 r0 = rval;
1857 }
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1859 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1860 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001861# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001862 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1863 return -1;
1864 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001865 regs.psr |= PSR_C;
1866 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001867 }
1868 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001869 regs.psr &= ~PSR_C;
1870 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001871 }
1872 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1873 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001874# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001875 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1876 return -1;
1877 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001878 regs.tstate |= 0x1100000000UL;
1879 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001880 }
1881 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001882 regs.tstate &= ~0x1100000000UL;
1883 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001884 }
1885 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1886 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001887# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 r28 = error ? -error : rval;
1889 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001891# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001892 r0 = error ? -error : rval;
1893 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1894 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001895# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001896 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001899# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001900#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001901
Roland McGrathb69f81b2002-12-21 23:25:18 +00001902#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001903 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1904 error << 24) < 0 ||
1905 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001906 return -1;
1907#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001908
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909#ifdef SVR4
1910 /* XXX no clue */
1911 return -1;
1912#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001913
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914#ifdef FREEBSD
1915 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001916 perror("pread");
1917 return -1;
1918 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919 if (error) {
1920 regs.r_eflags |= PSL_C;
1921 regs.r_eax = error;
1922 }
1923 else {
1924 regs.r_eflags &= ~PSL_C;
1925 regs.r_eax = rval;
1926 }
1927 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001928 perror("pwrite");
1929 return -1;
1930 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001931#endif /* FREEBSD */
1932
1933 /* All branches reach here on success (only). */
1934 tcp->u_error = error;
1935 tcp->u_rval = rval;
1936 return 0;
1937}
1938
Roland McGratha4d48532005-06-08 20:45:28 +00001939static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001940syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001941{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001942#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001943#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001944 {
1945 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001946 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1947 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001948 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001949 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001950 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001951 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001952 return -1;
1953 }
1954 }
1955#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956 {
1957 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001958 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1959 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001960 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001961 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001963 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1964 * for scno somewhere above here!
1965 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001966 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967 return -1;
1968 }
1969 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001970#elif defined (IA64)
1971 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001972 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001973 unsigned long *out0, cfm, sof, sol, i;
1974 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001975 /* be backwards compatible with kernel < 2.4.4... */
1976# ifndef PT_RBS_END
1977# define PT_RBS_END PT_AR_BSP
1978# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001979
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001980 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001981 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001982 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001983 return -1;
1984
1985 sof = (cfm >> 0) & 0x7f;
1986 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001987 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001988
1989 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1990 && sysent[tcp->scno].nargs != -1)
1991 tcp->u_nargs = sysent[tcp->scno].nargs;
1992 else
1993 tcp->u_nargs = MAX_ARGS;
1994 for (i = 0; i < tcp->u_nargs; ++i) {
1995 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1996 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1997 return -1;
1998 }
1999 } else {
2000 int i;
2001
2002 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002003 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002004 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002005 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002006 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002007 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002008 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002009 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002010 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002011 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002012 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002013 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002014 return -1;
2015
2016 for (i = 0; i < 6; ++i)
2017 /* truncate away IVE sign-extension */
2018 tcp->u_arg[i] &= 0xffffffff;
2019
2020 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2021 && sysent[tcp->scno].nargs != -1)
2022 tcp->u_nargs = sysent[tcp->scno].nargs;
2023 else
2024 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002025 }
2026 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002027#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2028 /* N32 and N64 both use up to six registers. */
2029 {
2030 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002031 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002032
2033 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2034 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002035 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002036 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002037
Roland McGratheb9e2e82009-06-02 16:49:22 -07002038 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002039 return -1;
2040
Roland McGratheb9e2e82009-06-02 16:49:22 -07002041 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002042 tcp->u_arg[i] = regs[REG_A0 + i];
2043# if defined (LINUX_MIPSN32)
2044 tcp->ext_arg[i] = regs[REG_A0 + i];
2045# endif
2046 }
2047 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002048#elif defined (MIPS)
2049 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002050 long sp;
2051 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002052
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002053 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2054 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002055 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002056 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002057 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002058 if(upeek(tcp, REG_SP, &sp) < 0)
2059 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002060 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002061 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2062 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002063 }
2064 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2065 (char *)(tcp->u_arg + 4));
2066 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002067 for(i = 0; i < nargs; i++) {
2068 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2069 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002070 }
2071 }
2072 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002073#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002074# ifndef PT_ORIG_R3
2075# define PT_ORIG_R3 34
2076# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077 {
2078 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002079 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2080 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002081 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002082 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002083 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002084 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002085 (sizeof(unsigned long)*PT_ORIG_R3) :
2086 ((i+PT_R3)*sizeof(unsigned long)),
2087 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002088 return -1;
2089 }
2090 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002091#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002092 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002093 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002094
2095 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2096 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002097 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002098 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002100 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002101 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002102#elif defined (HPPA)
2103 {
2104 int i;
2105
2106 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2107 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002108 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002109 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002110 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002111 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002112 return -1;
2113 }
2114 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002115#elif defined(ARM)
2116 {
2117 int i;
2118
2119 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2120 tcp->u_nargs = sysent[tcp->scno].nargs;
2121 else
2122 tcp->u_nargs = MAX_ARGS;
2123 for (i = 0; i < tcp->u_nargs; i++)
2124 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002125 }
2126#elif defined(AVR32)
2127 tcp->u_nargs = sysent[tcp->scno].nargs;
2128 tcp->u_arg[0] = regs.r12;
2129 tcp->u_arg[1] = regs.r11;
2130 tcp->u_arg[2] = regs.r10;
2131 tcp->u_arg[3] = regs.r9;
2132 tcp->u_arg[4] = regs.r5;
2133 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002134#elif defined(BFIN)
2135 {
2136 int i;
2137 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2138
2139 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
2141 else
2142 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2143
2144 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002145 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002146 return -1;
2147 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002148#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002149 {
2150 int i;
2151 static int syscall_regs[] = {
2152 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2153 REG_REG0, REG_REG0+1, REG_REG0+2
2154 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002155
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002156 tcp->u_nargs = sysent[tcp->scno].nargs;
2157 for (i = 0; i < tcp->u_nargs; i++) {
2158 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2159 return -1;
2160 }
2161 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002162#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002163 {
2164 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002165 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002166 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2167
2168 /*
2169 * TODO: should also check that the number of arguments encoded
2170 * in the trap number matches the number strace expects.
2171 */
2172 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002173 assert(sysent[tcp->scno].nargs <
2174 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002175 */
2176
2177 tcp->u_nargs = sysent[tcp->scno].nargs;
2178 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002179 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002180 return -1;
2181 }
2182 }
2183
Michal Ludvig0e035502002-09-23 15:41:01 +00002184#elif defined(X86_64)
2185 {
2186 int i;
2187 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2188 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002189 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002190 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002191
Michal Ludvig0e035502002-09-23 15:41:01 +00002192 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2193 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002194 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002195 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002196 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002197 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002198 return -1;
2199 }
2200 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002201#elif defined(CRISV10) || defined(CRISV32)
2202 {
2203 int i;
2204 static const int crisregs[] = {
2205 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2206 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2207 };
2208
2209 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2210 tcp->u_nargs = sysent[tcp->scno].nargs;
2211 else
2212 tcp->u_nargs = 0;
2213 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002214 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002215 return -1;
2216 }
2217 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002218#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002219 {
2220 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002221 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2222 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002223 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002224 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002225 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002226 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002227 return -1;
2228 }
2229 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002230#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231#endif /* LINUX */
2232#ifdef SUNOS4
2233 {
2234 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002235 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2236 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002237 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002238 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002239 for (i = 0; i < tcp->u_nargs; i++) {
2240 struct user *u;
2241
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002242 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2244 return -1;
2245 }
2246 }
2247#endif /* SUNOS4 */
2248#ifdef SVR4
2249#ifdef MIPS
2250 /*
2251 * SGI is broken: even though it has pr_sysarg, it doesn't
2252 * set them on system call entry. Get a clue.
2253 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002254 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 tcp->u_nargs = sysent[tcp->scno].nargs;
2256 else
2257 tcp->u_nargs = tcp->status.pr_nsysarg;
2258 if (tcp->u_nargs > 4) {
2259 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2260 4*sizeof(tcp->u_arg[0]));
2261 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2262 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2263 }
2264 else {
2265 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2266 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2267 }
John Hughes25299712001-03-06 10:10:06 +00002268#elif UNIXWARE >= 2
2269 /*
2270 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2271 */
2272 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2273 tcp->u_nargs = sysent[tcp->scno].nargs;
2274 else
2275 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2276 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2277 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2278#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002279 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002280 tcp->u_nargs = sysent[tcp->scno].nargs;
2281 else
2282 tcp->u_nargs = tcp->status.pr_nsysarg;
2283 {
2284 int i;
2285 for (i = 0; i < tcp->u_nargs; i++)
2286 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2287 }
John Hughes25299712001-03-06 10:10:06 +00002288#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002289 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 tcp->u_nargs = sysent[tcp->scno].nargs;
2291 else
2292 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002293 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002295#else
2296 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299#ifdef FREEBSD
2300 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2301 sysent[tcp->scno].nargs > tcp->status.val)
2302 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002303 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002304 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002305 if (tcp->u_nargs < 0)
2306 tcp->u_nargs = 0;
2307 if (tcp->u_nargs > MAX_ARGS)
2308 tcp->u_nargs = MAX_ARGS;
2309 switch(regs.r_eax) {
2310 case SYS___syscall:
2311 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2312 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002313 break;
2314 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002315 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2316 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002317 break;
2318 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002319 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2320 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002321 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002322 }
2323#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324 return 1;
2325}
2326
2327int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002328trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002329{
2330 int sys_res;
2331 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002332 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002333
2334 if (tcp->flags & TCB_INSYSCALL) {
2335 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002337 /* Measure the exit time as early as possible to avoid errors. */
2338 if (dtime)
2339 gettimeofday(&tv, NULL);
2340
Roland McGratheb9e2e82009-06-02 16:49:22 -07002341 /* BTW, why we don't just memorize syscall no. on entry
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002342 * in tcp->something?
2343 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002344 scno_good = res = get_scno(tcp);
2345 if (res == 0)
2346 return res;
2347 if (res == 1)
2348 res = syscall_fixup(tcp);
2349 if (res == 0)
2350 return res;
2351 if (res == 1)
2352 res = get_error(tcp);
2353 if (res == 0)
2354 return res;
2355 if (res == 1)
2356 internal_syscall(tcp);
2357
2358 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002359 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002360 tcp->flags &= ~TCB_INSYSCALL;
2361 return 0;
2362 }
2363
2364 if (tcp->flags & TCB_REPRINT) {
2365 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002366 tprintf("<... ");
2367 if (scno_good != 1)
2368 tprintf("????");
2369 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2370 tprintf("syscall_%lu", tcp->scno);
2371 else
2372 tprintf("%s", sysent[tcp->scno].sys_name);
2373 tprintf(" resumed> ");
Pavel Machek4dc3b142000-02-01 17:58:41 +00002374 }
2375
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002376 if (cflag)
2377 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002378
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002379 if (res != 1) {
2380 tprintf(") ");
2381 tabto(acolumn);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002382 tprintf("= ? <unavailable>");
2383 printtrailer();
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002384 tcp->flags &= ~TCB_INSYSCALL;
2385 return res;
2386 }
2387
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002388 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002389 || (qual_flags[tcp->scno] & QUAL_RAW))
2390 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002391 else {
2392 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002393 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002394 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002395 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002396 u_error = tcp->u_error;
2397 tprintf(") ");
2398 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002399 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2400 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002401 if (u_error)
2402 tprintf("= -1 (errno %ld)", u_error);
2403 else
2404 tprintf("= %#lx", tcp->u_rval);
2405 }
2406 else if (!(sys_res & RVAL_NONE) && u_error) {
2407 switch (u_error) {
2408#ifdef LINUX
2409 case ERESTARTSYS:
2410 tprintf("= ? ERESTARTSYS (To be restarted)");
2411 break;
2412 case ERESTARTNOINTR:
2413 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2414 break;
2415 case ERESTARTNOHAND:
2416 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2417 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002418 case ERESTART_RESTARTBLOCK:
2419 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2420 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002421#endif /* LINUX */
2422 default:
2423 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002424 if (u_error < 0)
2425 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002426 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002427 tprintf("%s (%s)", errnoent[u_error],
2428 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002429 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002430 tprintf("ERRNO_%ld (%s)", u_error,
2431 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002432 break;
2433 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002434 if ((sys_res & RVAL_STR) && tcp->auxstr)
2435 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002436 }
2437 else {
2438 if (sys_res & RVAL_NONE)
2439 tprintf("= ?");
2440 else {
2441 switch (sys_res & RVAL_MASK) {
2442 case RVAL_HEX:
2443 tprintf("= %#lx", tcp->u_rval);
2444 break;
2445 case RVAL_OCTAL:
2446 tprintf("= %#lo", tcp->u_rval);
2447 break;
2448 case RVAL_UDECIMAL:
2449 tprintf("= %lu", tcp->u_rval);
2450 break;
2451 case RVAL_DECIMAL:
2452 tprintf("= %ld", tcp->u_rval);
2453 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002454#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002455 case RVAL_LHEX:
2456 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002457 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002458 case RVAL_LOCTAL:
2459 tprintf("= %#llo", tcp->u_lrval);
2460 break;
2461 case RVAL_LUDECIMAL:
2462 tprintf("= %llu", tcp->u_lrval);
2463 break;
2464 case RVAL_LDECIMAL:
2465 tprintf("= %lld", tcp->u_lrval);
2466 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002467#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002468 default:
2469 fprintf(stderr,
2470 "invalid rval format\n");
2471 break;
2472 }
2473 }
2474 if ((sys_res & RVAL_STR) && tcp->auxstr)
2475 tprintf(" (%s)", tcp->auxstr);
2476 }
2477 if (dtime) {
2478 tv_sub(&tv, &tv, &tcp->etime);
2479 tprintf(" <%ld.%06ld>",
2480 (long) tv.tv_sec, (long) tv.tv_usec);
2481 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002482 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002483
2484 dumpio(tcp);
2485 if (fflush(tcp->outf) == EOF)
2486 return -1;
2487 tcp->flags &= ~TCB_INSYSCALL;
2488 return 0;
2489 }
2490
2491 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002492 scno_good = res = get_scno(tcp);
2493 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002494 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002495 if (res == 1)
2496 res = syscall_fixup(tcp);
2497 if (res == 0)
2498 return res;
2499 if (res == 1)
2500 res = syscall_enter(tcp);
2501 if (res == 0)
2502 return res;
2503
2504 if (res != 1) {
2505 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002506 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002507 tcp_last = tcp;
2508 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002509 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002510 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2511 tprintf("syscall_%lu(", tcp->scno);
2512 else
2513 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002514 /*
2515 * " <unavailable>" will be added later by the code which
2516 * detects ptrace errors.
2517 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002518 tcp->flags |= TCB_INSYSCALL;
2519 return res;
2520 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002521
Roland McGrath17352792005-06-07 23:21:26 +00002522 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002523#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002524 case SYS_socketcall:
2525 decode_subcall(tcp, SYS_socket_subcall,
2526 SYS_socket_nsubcalls, deref_style);
2527 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002528#endif
2529#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002530 case SYS_ipc:
2531 decode_subcall(tcp, SYS_ipc_subcall,
2532 SYS_ipc_nsubcalls, shift_style);
2533 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002534#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535#ifdef SVR4
2536#ifdef SYS_pgrpsys_subcall
2537 case SYS_pgrpsys:
2538 decode_subcall(tcp, SYS_pgrpsys_subcall,
2539 SYS_pgrpsys_nsubcalls, shift_style);
2540 break;
2541#endif /* SYS_pgrpsys_subcall */
2542#ifdef SYS_sigcall_subcall
2543 case SYS_sigcall:
2544 decode_subcall(tcp, SYS_sigcall_subcall,
2545 SYS_sigcall_nsubcalls, mask_style);
2546 break;
2547#endif /* SYS_sigcall_subcall */
2548 case SYS_msgsys:
2549 decode_subcall(tcp, SYS_msgsys_subcall,
2550 SYS_msgsys_nsubcalls, shift_style);
2551 break;
2552 case SYS_shmsys:
2553 decode_subcall(tcp, SYS_shmsys_subcall,
2554 SYS_shmsys_nsubcalls, shift_style);
2555 break;
2556 case SYS_semsys:
2557 decode_subcall(tcp, SYS_semsys_subcall,
2558 SYS_semsys_nsubcalls, shift_style);
2559 break;
2560#if 0 /* broken */
2561 case SYS_utssys:
2562 decode_subcall(tcp, SYS_utssys_subcall,
2563 SYS_utssys_nsubcalls, shift_style);
2564 break;
2565#endif
2566 case SYS_sysfs:
2567 decode_subcall(tcp, SYS_sysfs_subcall,
2568 SYS_sysfs_nsubcalls, shift_style);
2569 break;
2570 case SYS_spcall:
2571 decode_subcall(tcp, SYS_spcall_subcall,
2572 SYS_spcall_nsubcalls, shift_style);
2573 break;
2574#ifdef SYS_context_subcall
2575 case SYS_context:
2576 decode_subcall(tcp, SYS_context_subcall,
2577 SYS_context_nsubcalls, shift_style);
2578 break;
2579#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002580#ifdef SYS_door_subcall
2581 case SYS_door:
2582 decode_subcall(tcp, SYS_door_subcall,
2583 SYS_door_nsubcalls, door_style);
2584 break;
2585#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002586#ifdef SYS_kaio_subcall
2587 case SYS_kaio:
2588 decode_subcall(tcp, SYS_kaio_subcall,
2589 SYS_kaio_nsubcalls, shift_style);
2590 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002591#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002593#ifdef FREEBSD
2594 case SYS_msgsys:
2595 case SYS_shmsys:
2596 case SYS_semsys:
2597 decode_subcall(tcp, 0, 0, table_style);
2598 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002599#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600#ifdef SUNOS4
2601 case SYS_semsys:
2602 decode_subcall(tcp, SYS_semsys_subcall,
2603 SYS_semsys_nsubcalls, shift_style);
2604 break;
2605 case SYS_msgsys:
2606 decode_subcall(tcp, SYS_msgsys_subcall,
2607 SYS_msgsys_nsubcalls, shift_style);
2608 break;
2609 case SYS_shmsys:
2610 decode_subcall(tcp, SYS_shmsys_subcall,
2611 SYS_shmsys_nsubcalls, shift_style);
2612 break;
2613#endif
2614 }
2615
2616 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002617 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002618 tcp->flags |= TCB_INSYSCALL;
2619 return 0;
2620 }
2621
2622 if (cflag) {
2623 gettimeofday(&tcp->etime, NULL);
2624 tcp->flags |= TCB_INSYSCALL;
2625 return 0;
2626 }
2627
2628 printleader(tcp);
2629 tcp->flags &= ~TCB_REPRINT;
2630 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002631 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002632 tprintf("syscall_%lu(", tcp->scno);
2633 else
2634 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002635 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002636 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2637 sys_res = printargs(tcp);
2638 else
2639 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2640 if (fflush(tcp->outf) == EOF)
2641 return -1;
2642 tcp->flags |= TCB_INSYSCALL;
2643 /* Measure the entrance time as late as possible to avoid errors. */
2644 if (dtime)
2645 gettimeofday(&tcp->etime, NULL);
2646 return sys_res;
2647}
2648
2649int
2650printargs(tcp)
2651struct tcb *tcp;
2652{
2653 if (entering(tcp)) {
2654 int i;
2655
2656 for (i = 0; i < tcp->u_nargs; i++)
2657 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2658 }
2659 return 0;
2660}
2661
2662long
2663getrval2(tcp)
2664struct tcb *tcp;
2665{
2666 long val = -1;
2667
2668#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002669#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002670 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002671 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002672 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002673 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002674#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002675 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002676 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002677#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002678 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002679 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002680#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681#endif /* LINUX */
2682
2683#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002684 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002685 return -1;
2686#endif /* SUNOS4 */
2687
2688#ifdef SVR4
2689#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002690 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002691#endif /* SPARC */
2692#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002693 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002695#ifdef X86_64
2696 val = tcp->status.PR_REG[RDX];
2697#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002699 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700#endif /* MIPS */
2701#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002702
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002703#ifdef FREEBSD
2704 struct reg regs;
2705 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2706 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708 return val;
2709}
2710
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002711#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002712/*
2713 * Apparently, indirect system calls have already be converted by ptrace(2),
2714 * so if you see "indir" this program has gone astray.
2715 */
2716int
2717sys_indir(tcp)
2718struct tcb *tcp;
2719{
2720 int i, scno, nargs;
2721
2722 if (entering(tcp)) {
2723 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2724 fprintf(stderr, "Bogus syscall: %u\n", scno);
2725 return 0;
2726 }
2727 nargs = sysent[scno].nargs;
2728 tprintf("%s", sysent[scno].sys_name);
2729 for (i = 0; i < nargs; i++)
2730 tprintf(", %#lx", tcp->u_arg[i+1]);
2731 }
2732 return 0;
2733}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002734#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002735
2736int
2737is_restart_error(struct tcb *tcp)
2738{
2739#ifdef LINUX
2740 if (!syserror(tcp))
2741 return 0;
2742 switch (tcp->u_error) {
2743 case ERESTARTSYS:
2744 case ERESTARTNOINTR:
2745 case ERESTARTNOHAND:
2746 case ERESTART_RESTARTBLOCK:
2747 return 1;
2748 default:
2749 break;
2750 }
2751#endif /* LINUX */
2752 return 0;
2753}