blob: f33ae4ce3ef393007944485505755eaf583d29d4 [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. Levin257e1572009-12-26 17:55:24 +0000682#ifdef LINUX
683 || sys_clone == func
684#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685#if UNIXWARE > 2
686 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000688 )
689 return internal_fork(tcp);
690
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000691 if ( sys_execve == func
692#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
693 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000695#if UNIXWARE > 2
696 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698 )
699 return internal_exec(tcp);
700
701 if ( sys_waitpid == func
702 || sys_wait4 == func
703#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
704 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000705#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000706#ifdef ALPHA
707 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000708#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 )
710 return internal_wait(tcp, 2);
711
712#if defined(LINUX) || defined(SVR4)
713 if (sys_waitid == func)
714 return internal_wait(tcp, 3);
715#endif
716
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717 return 0;
718}
719
Wichert Akkermanc7926982000-04-10 22:22:31 +0000720
721#ifdef LINUX
722#if defined (I386)
723 static long eax;
724#elif defined (IA64)
725 long r8, r10, psr;
726 long ia32 = 0;
727#elif defined (POWERPC)
728 static long result,flags;
729#elif defined (M68K)
Andreas Schwabffca9e32010-05-28 20:53:14 +0200730 static long d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000731#elif defined(BFIN)
732 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000733#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000734 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735#elif defined (ALPHA)
736 static long r0;
737 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000738#elif defined(AVR32)
739 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000740#elif defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -0400741 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000742 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000743#elif defined(LINUX_MIPSN32)
744 static long long a3;
745 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000746#elif defined(MIPS)
747 static long a3;
748 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000749#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750 static long gpr2;
751 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000752 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000753#elif defined(HPPA)
754 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000755#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000756 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000757#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000758 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000759#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000760 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000761#elif defined(CRISV10) || defined(CRISV32)
762 static long r10;
Roland McGrath761b5d72002-12-15 23:58:31 +0000763#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000765#ifdef FREEBSD
766 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000767#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000768
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000770get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000771{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000775# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000776 if (tcp->flags & TCB_WAITEXECVE) {
777 /*
778 * When the execve system call completes successfully, the
779 * new process still has -ENOSYS (old style) or __NR_execve
780 * (new style) in gpr2. We cannot recover the scno again
781 * by disassembly, because the image that executed the
782 * syscall is gone now. Fortunately, we don't want it. We
783 * leave the flag set so that syscall_fixup can fake the
784 * result.
785 */
786 if (tcp->flags & TCB_INSYSCALL)
787 return 1;
788 /*
789 * This is the SIGTRAP after execve. We cannot try to read
790 * the system call here either.
791 */
792 tcp->flags &= ~TCB_WAITEXECVE;
793 return 0;
794 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000795
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000796 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000797 return -1;
798
799 if (syscall_mode != -ENOSYS) {
800 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000801 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000802 */
803 scno = syscall_mode;
804 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000805 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 * Old style of "passing" the scno via the SVC instruction.
807 */
808
809 long opcode, offset_reg, tmp;
810 void * svc_addr;
811 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
812 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
813 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
814 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000815
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000816 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000817 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000818 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000819 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000820 if (errno) {
821 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000823 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000824
825 /*
826 * We have to check if the SVC got executed directly or via an
827 * EXECUTE instruction. In case of EXECUTE it is necessary to do
828 * instruction decoding to derive the system call number.
829 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
830 * so that this doesn't work if a SVC opcode is part of an EXECUTE
831 * opcode. Since there is no way to find out the opcode size this
832 * is the best we can do...
833 */
834
835 if ((opcode & 0xff00) == 0x0a00) {
836 /* SVC opcode */
837 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000838 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000839 else {
840 /* SVC got executed by EXECUTE instruction */
841
842 /*
843 * Do instruction decoding of EXECUTE. If you really want to
844 * understand this, read the Principles of Operations.
845 */
846 svc_addr = (void *) (opcode & 0xfff);
847
848 tmp = 0;
849 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000850 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 return -1;
852 svc_addr += tmp;
853
854 tmp = 0;
855 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000856 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000857 return -1;
858 svc_addr += tmp;
859
Denys Vlasenkofb036672009-01-23 16:30:26 +0000860 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000861 if (errno)
862 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000863# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000864 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000865# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000866 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000867# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 tmp = 0;
869 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000870 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000871 return -1;
872
873 scno = (scno | tmp) & 0xff;
874 }
875 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000876# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000877 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000878 return -1;
879 if (!(tcp->flags & TCB_INSYSCALL)) {
880 /* Check if we return from execve. */
881 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
882 tcp->flags &= ~TCB_WAITEXECVE;
883 return 0;
884 }
885 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200886
887# ifdef POWERPC64
888 if (!(tcp->flags & TCB_INSYSCALL)) {
889 static int currpers = -1;
890 long val;
891 int pid = tcp->pid;
892
893 /* Check for 64/32 bit mode. */
894 if (upeek(tcp, sizeof (unsigned long)*PT_MSR, &val) < 0)
895 return -1;
896 /* SF is bit 0 of MSR */
897 if (val < 0)
898 currpers = 0;
899 else
900 currpers = 1;
901 if (currpers != current_personality) {
902 static const char *const names[] = {"64 bit", "32 bit"};
903 set_personality(currpers);
904 printf("[ Process PID=%d runs in %s mode. ]\n",
905 pid, names[current_personality]);
906 }
907 }
908# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000909# elif defined(AVR32)
910 /*
911 * Read complete register set in one go.
912 */
913 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
914 return -1;
915
916 /*
917 * We only need to grab the syscall number on syscall entry.
918 */
919 if (!(tcp->flags & TCB_INSYSCALL)) {
920 scno = regs.r8;
921
922 /* Check if we return from execve. */
923 if (tcp->flags & TCB_WAITEXECVE) {
924 tcp->flags &= ~TCB_WAITEXECVE;
925 return 0;
926 }
927 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000928# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000929 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000930 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000931# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000932 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000933 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000934# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000935 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000936 return -1;
937
Roland McGrath761b5d72002-12-15 23:58:31 +0000938 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000939 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000940 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000941 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000942
943 /* Check CS register value. On x86-64 linux it is:
944 * 0x33 for long mode (64 bit)
945 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000946 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 * to be cached.
948 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000949 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000951 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 case 0x23: currpers = 1; break;
953 case 0x33: currpers = 0; break;
954 default:
955 fprintf(stderr, "Unknown value CS=0x%02X while "
956 "detecting personality of process "
957 "PID=%d\n", (int)val, pid);
958 currpers = current_personality;
959 break;
960 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000961# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000962 /* This version analyzes the opcode of a syscall instruction.
963 * (int 0x80 on i386 vs. syscall on x86-64)
964 * It works, but is too complicated.
965 */
966 unsigned long val, rip, i;
967
Denys Vlasenko8236f252009-01-02 18:10:08 +0000968 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000970
Michal Ludvig0e035502002-09-23 15:41:01 +0000971 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000972 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000973 errno = 0;
974
Denys Vlasenko8236f252009-01-02 18:10:08 +0000975 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 if (errno)
977 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000978 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000979 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000980 /* x86-64: syscall = 0x0f 0x05 */
981 case 0x050f: currpers = 0; break;
982 /* i386: int 0x80 = 0xcd 0x80 */
983 case 0x80cd: currpers = 1; break;
984 default:
985 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000986 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000987 "Unknown syscall opcode (0x%04X) while "
988 "detecting personality of process "
989 "PID=%d\n", (int)call, pid);
990 break;
991 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000992# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000993 if (currpers != current_personality) {
994 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000995 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000996 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000997 pid, names[current_personality]);
998 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000999 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001000# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001001# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001002 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001003 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001004 if (!(tcp->flags & TCB_INSYSCALL)) {
1005 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001006 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001007 return -1;
1008 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001009 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001010 return -1;
1011 }
Roland McGrathba954762003-03-05 06:29:06 +00001012 /* Check if we return from execve. */
1013 if (tcp->flags & TCB_WAITEXECVE) {
1014 tcp->flags &= ~TCB_WAITEXECVE;
1015 return 0;
1016 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001017 } else {
1018 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001019 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001020 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001021 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001022 return -1;
1023 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001024# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001025 /*
1026 * Read complete register set in one go.
1027 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001028 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001029 return -1;
1030
1031 /*
1032 * We only need to grab the syscall number on syscall entry.
1033 */
1034 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001035 if (!(tcp->flags & TCB_INSYSCALL)) {
1036 /* Check if we return from execve. */
1037 if (tcp->flags & TCB_WAITEXECVE) {
1038 tcp->flags &= ~TCB_WAITEXECVE;
1039 return 0;
1040 }
1041 }
1042
Roland McGrath0f87c492003-06-03 23:29:04 +00001043 /*
1044 * Note: we only deal with only 32-bit CPUs here.
1045 */
1046 if (regs.ARM_cpsr & 0x20) {
1047 /*
1048 * Get the Thumb-mode system call number
1049 */
1050 scno = regs.ARM_r7;
1051 } else {
1052 /*
1053 * Get the ARM-mode system call number
1054 */
1055 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001056 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001057 if (errno)
1058 return -1;
1059
1060 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1061 tcp->flags &= ~TCB_WAITEXECVE;
1062 return 0;
1063 }
1064
Roland McGrathf691bd22006-04-25 07:34:41 +00001065 /* Handle the EABI syscall convention. We do not
1066 bother converting structures between the two
1067 ABIs, but basic functionality should work even
1068 if strace and the traced program have different
1069 ABIs. */
1070 if (scno == 0xef000000) {
1071 scno = regs.ARM_r7;
1072 } else {
1073 if ((scno & 0x0ff00000) != 0x0f900000) {
1074 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1075 scno);
1076 return -1;
1077 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001078
Roland McGrathf691bd22006-04-25 07:34:41 +00001079 /*
1080 * Fixup the syscall number
1081 */
1082 scno &= 0x000fffff;
1083 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001084 }
Roland McGrath56703312008-05-20 01:35:55 +00001085 if (scno & 0x0f0000) {
1086 /*
1087 * Handle ARM specific syscall
1088 */
1089 set_personality(1);
1090 scno &= 0x0000ffff;
1091 } else
1092 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001093
1094 if (tcp->flags & TCB_INSYSCALL) {
1095 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1096 tcp->flags &= ~TCB_INSYSCALL;
1097 }
1098 } else {
1099 if (!(tcp->flags & TCB_INSYSCALL)) {
1100 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1101 tcp->flags |= TCB_INSYSCALL;
1102 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001104# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001107# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001108 unsigned long long regs[38];
1109
Roland McGratheb9e2e82009-06-02 16:49:22 -07001110 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001111 return -1;
1112 a3 = regs[REG_A3];
1113 r2 = regs[REG_V0];
1114
1115 if(!(tcp->flags & TCB_INSYSCALL)) {
1116 scno = r2;
1117
1118 /* Check if we return from execve. */
1119 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1120 tcp->flags &= ~TCB_WAITEXECVE;
1121 return 0;
1122 }
1123
1124 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 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001132# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001133 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001134 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001135 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001136 if (upeek(tcp, REG_V0, &scno) < 0)
1137 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001138
Roland McGrath542c2c62008-05-20 01:11:56 +00001139 /* Check if we return from execve. */
1140 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1141 tcp->flags &= ~TCB_WAITEXECVE;
1142 return 0;
1143 }
1144
Wichert Akkermanf90da011999-10-31 21:15:38 +00001145 if (scno < 0 || scno > nsyscalls) {
1146 if(a3 == 0 || a3 == -1) {
1147 if(debug)
1148 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1149 return 0;
1150 }
1151 }
1152 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001153 if (upeek(tcp, REG_V0, &r2) < 0)
1154 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001155 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001156# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001157 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158 return -1;
1159
1160 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001161 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 return -1;
1163
1164 /* Check if we return from execve. */
1165 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1166 tcp->flags &= ~TCB_WAITEXECVE;
1167 return 0;
1168 }
1169
1170 /*
1171 * Do some sanity checks to figure out if it's
1172 * really a syscall entry
1173 */
1174 if (scno < 0 || scno > nsyscalls) {
1175 if (a3 == 0 || a3 == -1) {
1176 if (debug)
1177 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1178 return 0;
1179 }
1180 }
1181 }
1182 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001183 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 return -1;
1185 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001186# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001188 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 return -1;
1190
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001191 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192 if (!(tcp->flags & TCB_INSYSCALL)) {
1193 /* Retrieve the syscall trap instruction. */
1194 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001196 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001197 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001198# else
1199 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001200# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201 if (errno)
1202 return -1;
1203
1204 /* Disassemble the trap to see what personality to use. */
1205 switch (trap) {
1206 case 0x91d02010:
1207 /* Linux/SPARC syscall trap. */
1208 set_personality(0);
1209 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001210 case 0x91d0206d:
1211 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001212 set_personality(2);
1213 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 case 0x91d02000:
1215 /* SunOS syscall trap. (pers 1) */
1216 fprintf(stderr,"syscall: SunOS no support\n");
1217 return -1;
1218 case 0x91d02008:
1219 /* Solaris 2.x syscall trap. (per 2) */
1220 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001221 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001222 case 0x91d02009:
1223 /* NetBSD/FreeBSD syscall trap. */
1224 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1225 return -1;
1226 case 0x91d02027:
1227 /* Solaris 2.x gettimeofday */
1228 set_personality(1);
1229 break;
1230 default:
1231 /* Unknown syscall trap. */
1232 if(tcp->flags & TCB_WAITEXECVE) {
1233 tcp->flags &= ~TCB_WAITEXECVE;
1234 return 0;
1235 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001236# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001237 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001238# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001239 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001240# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241 return -1;
1242 }
1243
1244 /* Extract the system call number from the registers. */
1245 if (trap == 0x91d02027)
1246 scno = 156;
1247 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001248 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001250 scno = regs.u_regs[U_REG_O0];
1251 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 +00001252 }
1253 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001254# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001255 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001256 return -1;
1257 if (!(tcp->flags & TCB_INSYSCALL)) {
1258 /* Check if we return from execve. */
1259 if ((tcp->flags & TCB_WAITEXECVE)) {
1260 tcp->flags &= ~TCB_WAITEXECVE;
1261 return 0;
1262 }
1263 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001264# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001265 /*
1266 * In the new syscall ABI, the system call number is in R3.
1267 */
1268 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1269 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001270
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001271 if (scno < 0) {
1272 /* Odd as it may seem, a glibc bug has been known to cause
1273 glibc to issue bogus negative syscall numbers. So for
1274 our purposes, make strace print what it *should* have been */
1275 long correct_scno = (scno & 0xff);
1276 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001277 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001278 "Detected glibc bug: bogus system call"
1279 " number = %ld, correcting to %ld\n",
1280 scno,
1281 correct_scno);
1282 scno = correct_scno;
1283 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001284
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001285 if (!(tcp->flags & TCB_INSYSCALL)) {
1286 /* Check if we return from execve. */
1287 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1288 tcp->flags &= ~TCB_WAITEXECVE;
1289 return 0;
1290 }
1291 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001292# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001293 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001294 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001295 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001296
1297 if (!(tcp->flags & TCB_INSYSCALL)) {
1298 /* Check if we return from execve. */
1299 if (tcp->flags & TCB_WAITEXECVE) {
1300 tcp->flags &= ~TCB_WAITEXECVE;
1301 return 0;
1302 }
1303 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001304# elif defined(CRISV10) || defined(CRISV32)
1305 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1306 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001307# elif defined(TILE)
1308 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1309 return -1;
1310
1311 if (!(tcp->flags & TCB_INSYSCALL)) {
1312 /* Check if we return from execve. */
1313 if (tcp->flags & TCB_WAITEXECVE) {
1314 tcp->flags &= ~TCB_WAITEXECVE;
1315 return 0;
1316 }
1317 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001318# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001319#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001320
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001322 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001323 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001324#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001325 /* new syscall ABI returns result in R0 */
1326 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1327 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001328#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001329 /* ABI defines result returned in r9 */
1330 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1331 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001333
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001334#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001335# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001336 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001337# else
1338# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001339 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001340# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001342 perror("pread");
1343 return -1;
1344 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345 switch (regs.r_eax) {
1346 case SYS_syscall:
1347 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001348 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1349 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001350 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001351 scno = regs.r_eax;
1352 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001354# endif /* FREEBSD */
1355# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001357
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001358 if (!(tcp->flags & TCB_INSYSCALL))
1359 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001360 return 1;
1361}
1362
Pavel Machek4dc3b142000-02-01 17:58:41 +00001363
Roland McGrath17352792005-06-07 23:21:26 +00001364long
1365known_scno(tcp)
1366struct tcb *tcp;
1367{
1368 long scno = tcp->scno;
1369 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1370 scno = sysent[scno].native_scno;
1371 else
1372 scno += NR_SYSCALL_BASE;
1373 return scno;
1374}
1375
Roland McGratheb9e2e82009-06-02 16:49:22 -07001376/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001377 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001378 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1379 * 1: ok, continue in trace_syscall().
1380 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001381 * ("????" etc) and bail out.
1382 */
Roland McGratha4d48532005-06-08 20:45:28 +00001383static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001384syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001385{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001386#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001387 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001388
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 if (
1392 scno == SYS_fork
1393#ifdef SYS_vfork
1394 || scno == SYS_vfork
1395#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001396#ifdef SYS_fork1
1397 || scno == SYS_fork1
1398#endif /* SYS_fork1 */
1399#ifdef SYS_forkall
1400 || scno == SYS_forkall
1401#endif /* SYS_forkall */
1402#ifdef SYS_rfork1
1403 || scno == SYS_rfork1
1404#endif /* SYS_fork1 */
1405#ifdef SYS_rforkall
1406 || scno == SYS_rforkall
1407#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408 ) {
1409 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001410 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001412 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413 }
1414 else {
1415 fprintf(stderr, "syscall: missing entry\n");
1416 tcp->flags |= TCB_INSYSCALL;
1417 }
1418 }
1419 }
1420 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001421 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001422 fprintf(stderr, "syscall: missing exit\n");
1423 tcp->flags &= ~TCB_INSYSCALL;
1424 }
1425 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001426#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001427#ifdef SUNOS4
1428 if (!(tcp->flags & TCB_INSYSCALL)) {
1429 if (scno == 0) {
1430 fprintf(stderr, "syscall: missing entry\n");
1431 tcp->flags |= TCB_INSYSCALL;
1432 }
1433 }
1434 else {
1435 if (scno != 0) {
1436 if (debug) {
1437 /*
1438 * This happens when a signal handler
1439 * for a signal which interrupted a
1440 * a system call makes another system call.
1441 */
1442 fprintf(stderr, "syscall: missing exit\n");
1443 }
1444 tcp->flags &= ~TCB_INSYSCALL;
1445 }
1446 }
1447#endif /* SUNOS4 */
1448#ifdef LINUX
1449#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001450 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451 return -1;
1452 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1453 if (debug)
1454 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1455 return 0;
1456 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001457#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001458 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001459 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001460 if (current_personality == 1)
1461 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001462 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1463 if (debug)
1464 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1465 return 0;
1466 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001467#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001468 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001469 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001470 if (syscall_mode != -ENOSYS)
1471 syscall_mode = tcp->scno;
1472 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001473 if (debug)
1474 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1475 return 0;
1476 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001477 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1478 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1479 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1480 /*
1481 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1482 * flag set for the post-execve SIGTRAP to see and reset.
1483 */
1484 gpr2 = 0;
1485 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486#elif defined (POWERPC)
1487# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001488 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001490 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001491 return -1;
1492 if (flags & SO_MASK)
1493 result = -result;
1494#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001495 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 return -1;
1497 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1498 if (debug)
1499 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1500 return 0;
1501 }
1502#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001503 /*
1504 * Nothing required
1505 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001506#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001507 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001508 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001509#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001510 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001511 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001512#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001513 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001514 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001515 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001516 return -1;
1517 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1518 if (debug)
1519 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1520 return 0;
1521 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001522#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001523 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001524 return -1;
1525 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1526 if (debug)
1527 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1528 return 0;
1529 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530#endif
1531#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001532 return 1;
1533}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001534
Roland McGrathc1e45922008-05-27 23:18:29 +00001535#ifdef LINUX
1536/*
1537 * Check the syscall return value register value for whether it is
1538 * a negated errno code indicating an error, or a success return value.
1539 */
1540static inline int
1541is_negated_errno(unsigned long int val)
1542{
1543 unsigned long int max = -(long int) nerrnos;
1544 if (personality_wordsize[current_personality] < sizeof(val)) {
1545 val = (unsigned int) val;
1546 max = (unsigned int) max;
1547 }
1548 return val > max;
1549}
1550#endif
1551
Roland McGratha4d48532005-06-08 20:45:28 +00001552static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001553get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001554{
1555 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001557# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001558 if (is_negated_errno(gpr2)) {
1559 tcp->u_rval = -1;
1560 u_error = -gpr2;
1561 }
1562 else {
1563 tcp->u_rval = gpr2;
1564 u_error = 0;
1565 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001566# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001567 if (is_negated_errno(eax)) {
1568 tcp->u_rval = -1;
1569 u_error = -eax;
1570 }
1571 else {
1572 tcp->u_rval = eax;
1573 u_error = 0;
1574 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001575# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001576 if (is_negated_errno(rax)) {
1577 tcp->u_rval = -1;
1578 u_error = -rax;
1579 }
1580 else {
1581 tcp->u_rval = rax;
1582 u_error = 0;
1583 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001584# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001585 if (ia32) {
1586 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001587
Roland McGrathc1e45922008-05-27 23:18:29 +00001588 err = (int)r8;
1589 if (is_negated_errno(err)) {
1590 tcp->u_rval = -1;
1591 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001592 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 else {
1594 tcp->u_rval = err;
1595 u_error = 0;
1596 }
1597 } else {
1598 if (r10) {
1599 tcp->u_rval = -1;
1600 u_error = r8;
1601 } else {
1602 tcp->u_rval = r8;
1603 u_error = 0;
1604 }
1605 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001606# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001607 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001608 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001609 u_error = r2;
1610 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001611 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001612 u_error = 0;
1613 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001614# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001615 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 tcp->u_rval = -1;
1617 u_error = -result;
1618 }
1619 else {
1620 tcp->u_rval = result;
1621 u_error = 0;
1622 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001623# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001624 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 tcp->u_rval = -1;
1626 u_error = -d0;
1627 }
1628 else {
1629 tcp->u_rval = d0;
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001633 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001635 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 }
1637 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001638 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 u_error = 0;
1640 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001641# elif defined(AVR32)
1642 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1643 tcp->u_rval = -1;
1644 u_error = -regs.r12;
1645 }
1646 else {
1647 tcp->u_rval = regs.r12;
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001651 if (is_negated_errno(r0)) {
1652 tcp->u_rval = -1;
1653 u_error = -r0;
1654 } else {
1655 tcp->u_rval = r0;
1656 u_error = 0;
1657 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001658# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 if (a3) {
1660 tcp->u_rval = -1;
1661 u_error = r0;
1662 }
1663 else {
1664 tcp->u_rval = r0;
1665 u_error = 0;
1666 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001667# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001668 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001670 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 }
1672 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001673 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 u_error = 0;
1675 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001676# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001677 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001678 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001679 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001680 }
1681 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001682 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001683 u_error = 0;
1684 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001685# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001686 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001687 tcp->u_rval = -1;
1688 u_error = -r28;
1689 }
1690 else {
1691 tcp->u_rval = r28;
1692 u_error = 0;
1693 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001694# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001695 /* interpret R0 as return value or error number */
1696 if (is_negated_errno(r0)) {
1697 tcp->u_rval = -1;
1698 u_error = -r0;
1699 }
1700 else {
1701 tcp->u_rval = r0;
1702 u_error = 0;
1703 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001704# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001705 /* interpret result as return value or error number */
1706 if (is_negated_errno(r9)) {
1707 tcp->u_rval = -1;
1708 u_error = -r9;
1709 }
1710 else {
1711 tcp->u_rval = r9;
1712 u_error = 0;
1713 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001714# elif defined(CRISV10) || defined(CRISV32)
1715 if (r10 && (unsigned) -r10 < nerrnos) {
1716 tcp->u_rval = -1;
1717 u_error = -r10;
1718 }
1719 else {
1720 tcp->u_rval = r10;
1721 u_error = 0;
1722 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001723# elif defined(TILE)
1724 long rval;
1725 /* interpret result as return value or error number */
1726 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1727 return -1;
1728 if (rval < 0 && rval > -nerrnos) {
1729 tcp->u_rval = -1;
1730 u_error = -rval;
1731 }
1732 else {
1733 tcp->u_rval = rval;
1734 u_error = 0;
1735 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001736# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737#endif /* LINUX */
1738#ifdef SUNOS4
1739 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001740 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741 return -1;
1742 u_error >>= 24; /* u_error is a char */
1743
1744 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001745 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 return -1;
1747#endif /* SUNOS4 */
1748#ifdef SVR4
1749#ifdef SPARC
1750 /* Judicious guessing goes a long way. */
1751 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1752 tcp->u_rval = -1;
1753 u_error = tcp->status.pr_reg[R_O0];
1754 }
1755 else {
1756 tcp->u_rval = tcp->status.pr_reg[R_O0];
1757 u_error = 0;
1758 }
1759#endif /* SPARC */
1760#ifdef I386
1761 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001762 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001764 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765 }
1766 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001767 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001768#ifdef HAVE_LONG_LONG
1769 tcp->u_lrval =
1770 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1771 tcp->status.PR_REG[EAX];
1772#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773 u_error = 0;
1774 }
1775#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001776#ifdef X86_64
1777 /* Wanna know how to kill an hour single-stepping? */
1778 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1779 tcp->u_rval = -1;
1780 u_error = tcp->status.PR_REG[RAX];
1781 }
1782 else {
1783 tcp->u_rval = tcp->status.PR_REG[RAX];
1784 u_error = 0;
1785 }
1786#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787#ifdef MIPS
1788 if (tcp->status.pr_reg[CTX_A3]) {
1789 tcp->u_rval = -1;
1790 u_error = tcp->status.pr_reg[CTX_V0];
1791 }
1792 else {
1793 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1794 u_error = 0;
1795 }
1796#endif /* MIPS */
1797#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001798#ifdef FREEBSD
1799 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001800 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001801 u_error = regs.r_eax;
1802 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001803 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001804 tcp->u_lrval =
1805 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1806 u_error = 0;
1807 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001808#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001809 tcp->u_error = u_error;
1810 return 1;
1811}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812
Roland McGrathb69f81b2002-12-21 23:25:18 +00001813int
1814force_result(tcp, error, rval)
1815 struct tcb *tcp;
1816 int error;
1817 long rval;
1818{
1819#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001820# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001821 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1823 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001824# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001825 eax = error ? -error : rval;
1826 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1827 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001828# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001830 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001831 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001832# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 if (ia32) {
1834 r8 = error ? -error : rval;
1835 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1836 return -1;
1837 }
1838 else {
1839 if (error) {
1840 r8 = error;
1841 r10 = -1;
1842 }
1843 else {
1844 r8 = rval;
1845 r10 = 0;
1846 }
1847 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1848 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1849 return -1;
1850 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001851# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001852 r0 = error ? -error : rval;
1853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1854 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001855# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001856 if (error) {
1857 r2 = error;
1858 a3 = -1;
1859 }
1860 else {
1861 r2 = rval;
1862 a3 = 0;
1863 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001864 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001865 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1866 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001867 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001868# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001869 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001870 return -1;
1871 if (error) {
1872 flags |= SO_MASK;
1873 result = error;
1874 }
1875 else {
1876 flags &= ~SO_MASK;
1877 result = rval;
1878 }
Roland McGratheb285352003-01-14 09:59:00 +00001879 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1880 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001881 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001882# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001883 d0 = error ? -error : rval;
1884 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1885 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001886# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001887 regs.ARM_r0 = error ? -error : rval;
1888 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001889 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001890# elif defined(AVR32)
1891 regs.r12 = error ? -error : rval;
1892 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1893 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001894# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001895 if (error) {
1896 a3 = -1;
1897 r0 = error;
1898 }
1899 else {
1900 a3 = 0;
1901 r0 = rval;
1902 }
1903 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1904 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1905 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001906# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001907 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1908 return -1;
1909 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001910 regs.psr |= PSR_C;
1911 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912 }
1913 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001914 regs.psr &= ~PSR_C;
1915 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001916 }
1917 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1918 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001919# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001920 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1921 return -1;
1922 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001923 regs.tstate |= 0x1100000000UL;
1924 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001925 }
1926 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001927 regs.tstate &= ~0x1100000000UL;
1928 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001929 }
1930 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1931 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001932# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001933 r28 = error ? -error : rval;
1934 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1935 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001936# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001937 r0 = error ? -error : rval;
1938 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1939 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001940# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001941 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001942 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1943 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001944# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001945#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001946
Roland McGrathb69f81b2002-12-21 23:25:18 +00001947#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001948 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1949 error << 24) < 0 ||
1950 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001951 return -1;
1952#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001953
Roland McGrathb69f81b2002-12-21 23:25:18 +00001954#ifdef SVR4
1955 /* XXX no clue */
1956 return -1;
1957#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001958
Roland McGrathb69f81b2002-12-21 23:25:18 +00001959#ifdef FREEBSD
1960 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001961 perror("pread");
1962 return -1;
1963 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001964 if (error) {
1965 regs.r_eflags |= PSL_C;
1966 regs.r_eax = error;
1967 }
1968 else {
1969 regs.r_eflags &= ~PSL_C;
1970 regs.r_eax = rval;
1971 }
1972 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001973 perror("pwrite");
1974 return -1;
1975 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001976#endif /* FREEBSD */
1977
1978 /* All branches reach here on success (only). */
1979 tcp->u_error = error;
1980 tcp->u_rval = rval;
1981 return 0;
1982}
1983
Roland McGratha4d48532005-06-08 20:45:28 +00001984static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001985syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001986{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001987#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001988#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001989 {
1990 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001991 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1992 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001993 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001994 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001995 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001996 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001997 return -1;
1998 }
1999 }
2000#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001 {
2002 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002003 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2004 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002005 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002006 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002007 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002008 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2009 * for scno somewhere above here!
2010 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002011 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002012 return -1;
2013 }
2014 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002015#elif defined (IA64)
2016 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002017 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002018 unsigned long *out0, cfm, sof, sol, i;
2019 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002020 /* be backwards compatible with kernel < 2.4.4... */
2021# ifndef PT_RBS_END
2022# define PT_RBS_END PT_AR_BSP
2023# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002024
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002025 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002026 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002027 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002028 return -1;
2029
2030 sof = (cfm >> 0) & 0x7f;
2031 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002032 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002033
2034 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2035 && sysent[tcp->scno].nargs != -1)
2036 tcp->u_nargs = sysent[tcp->scno].nargs;
2037 else
2038 tcp->u_nargs = MAX_ARGS;
2039 for (i = 0; i < tcp->u_nargs; ++i) {
2040 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2041 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2042 return -1;
2043 }
2044 } else {
2045 int i;
2046
2047 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002048 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002049 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002050 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002051 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002052 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002053 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002054 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002055 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002056 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002057 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002058 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002059 return -1;
2060
2061 for (i = 0; i < 6; ++i)
2062 /* truncate away IVE sign-extension */
2063 tcp->u_arg[i] &= 0xffffffff;
2064
2065 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2066 && sysent[tcp->scno].nargs != -1)
2067 tcp->u_nargs = sysent[tcp->scno].nargs;
2068 else
2069 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002070 }
2071 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002072#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2073 /* N32 and N64 both use up to six registers. */
2074 {
2075 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002076 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002077
2078 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2079 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002080 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002081 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002082
David Daney20037042010-02-09 21:22:30 +00002083 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002084 return -1;
2085
Roland McGratheb9e2e82009-06-02 16:49:22 -07002086 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002087 tcp->u_arg[i] = regs[REG_A0 + i];
2088# if defined (LINUX_MIPSN32)
2089 tcp->ext_arg[i] = regs[REG_A0 + i];
2090# endif
2091 }
2092 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002093#elif defined (MIPS)
2094 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002095 long sp;
2096 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002097
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002098 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2099 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002100 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002101 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002102 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002103 if(upeek(tcp, REG_SP, &sp) < 0)
2104 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002105 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002106 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2107 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002108 }
2109 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2110 (char *)(tcp->u_arg + 4));
2111 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002112 for(i = 0; i < nargs; i++) {
2113 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2114 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002115 }
2116 }
2117 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002119# ifndef PT_ORIG_R3
2120# define PT_ORIG_R3 34
2121# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002122 {
2123 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002124 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2125 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002126 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002127 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002128 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002129 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002130 (sizeof(unsigned long)*PT_ORIG_R3) :
2131 ((i+PT_R3)*sizeof(unsigned long)),
2132 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133 return -1;
2134 }
2135 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002136#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002138 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002139
2140 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2141 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002142 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002143 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002145 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002146 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002147#elif defined (HPPA)
2148 {
2149 int i;
2150
2151 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2152 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002153 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002154 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002155 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002156 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002157 return -1;
2158 }
2159 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002160#elif defined(ARM)
2161 {
2162 int i;
2163
2164 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2165 tcp->u_nargs = sysent[tcp->scno].nargs;
2166 else
2167 tcp->u_nargs = MAX_ARGS;
2168 for (i = 0; i < tcp->u_nargs; i++)
2169 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002170 }
2171#elif defined(AVR32)
2172 tcp->u_nargs = sysent[tcp->scno].nargs;
2173 tcp->u_arg[0] = regs.r12;
2174 tcp->u_arg[1] = regs.r11;
2175 tcp->u_arg[2] = regs.r10;
2176 tcp->u_arg[3] = regs.r9;
2177 tcp->u_arg[4] = regs.r5;
2178 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002179#elif defined(BFIN)
2180 {
2181 int i;
2182 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2183
2184 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2185 tcp->u_nargs = sysent[tcp->scno].nargs;
2186 else
2187 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2188
2189 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002190 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002191 return -1;
2192 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002193#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002194 {
2195 int i;
2196 static int syscall_regs[] = {
2197 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2198 REG_REG0, REG_REG0+1, REG_REG0+2
2199 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002200
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002201 tcp->u_nargs = sysent[tcp->scno].nargs;
2202 for (i = 0; i < tcp->u_nargs; i++) {
2203 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2204 return -1;
2205 }
2206 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002207#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002208 {
2209 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002210 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002211 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2212
2213 /*
2214 * TODO: should also check that the number of arguments encoded
2215 * in the trap number matches the number strace expects.
2216 */
2217 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002218 assert(sysent[tcp->scno].nargs <
2219 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002220 */
2221
2222 tcp->u_nargs = sysent[tcp->scno].nargs;
2223 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002224 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002225 return -1;
2226 }
2227 }
2228
Michal Ludvig0e035502002-09-23 15:41:01 +00002229#elif defined(X86_64)
2230 {
2231 int i;
2232 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2233 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002234 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002235 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002236
Michal Ludvig0e035502002-09-23 15:41:01 +00002237 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2238 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002239 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002240 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002241 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002242 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002243 return -1;
2244 }
2245 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002246#elif defined(CRISV10) || defined(CRISV32)
2247 {
2248 int i;
2249 static const int crisregs[] = {
2250 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2251 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2252 };
2253
2254 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2255 tcp->u_nargs = sysent[tcp->scno].nargs;
2256 else
2257 tcp->u_nargs = 0;
2258 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002259 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002260 return -1;
2261 }
2262 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002263#elif defined(TILE)
2264 {
2265 int i;
2266 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2267 tcp->u_nargs = sysent[tcp->scno].nargs;
2268 else
2269 tcp->u_nargs = MAX_ARGS;
2270 for (i = 0; i < tcp->u_nargs; ++i) {
2271 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2272 return -1;
2273 }
2274 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002275#elif defined (M68K)
2276 {
2277 int i;
2278 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2279 tcp->u_nargs = sysent[tcp->scno].nargs;
2280 else
2281 tcp->u_nargs = MAX_ARGS;
2282 for (i = 0; i < tcp->u_nargs; i++) {
2283 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2284 return -1;
2285 }
2286 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002287#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002288 {
2289 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002290 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2291 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002292 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002293 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002295 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002296 return -1;
2297 }
2298 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002299#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002300#endif /* LINUX */
2301#ifdef SUNOS4
2302 {
2303 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002304 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2305 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002306 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002307 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002308 for (i = 0; i < tcp->u_nargs; i++) {
2309 struct user *u;
2310
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002311 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002312 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2313 return -1;
2314 }
2315 }
2316#endif /* SUNOS4 */
2317#ifdef SVR4
2318#ifdef MIPS
2319 /*
2320 * SGI is broken: even though it has pr_sysarg, it doesn't
2321 * set them on system call entry. Get a clue.
2322 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002323 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002324 tcp->u_nargs = sysent[tcp->scno].nargs;
2325 else
2326 tcp->u_nargs = tcp->status.pr_nsysarg;
2327 if (tcp->u_nargs > 4) {
2328 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2329 4*sizeof(tcp->u_arg[0]));
2330 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2331 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2332 }
2333 else {
2334 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2335 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2336 }
John Hughes25299712001-03-06 10:10:06 +00002337#elif UNIXWARE >= 2
2338 /*
2339 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2340 */
2341 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2342 tcp->u_nargs = sysent[tcp->scno].nargs;
2343 else
2344 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2345 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2346 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2347#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002349 tcp->u_nargs = sysent[tcp->scno].nargs;
2350 else
2351 tcp->u_nargs = tcp->status.pr_nsysarg;
2352 {
2353 int i;
2354 for (i = 0; i < tcp->u_nargs; i++)
2355 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2356 }
John Hughes25299712001-03-06 10:10:06 +00002357#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002359 tcp->u_nargs = sysent[tcp->scno].nargs;
2360 else
2361 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002362 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002363 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002364#else
2365 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002366#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002367#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002368#ifdef FREEBSD
2369 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2370 sysent[tcp->scno].nargs > tcp->status.val)
2371 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002372 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002373 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002374 if (tcp->u_nargs < 0)
2375 tcp->u_nargs = 0;
2376 if (tcp->u_nargs > MAX_ARGS)
2377 tcp->u_nargs = MAX_ARGS;
2378 switch(regs.r_eax) {
2379 case SYS___syscall:
2380 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2381 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002382 break;
2383 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002384 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2385 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002386 break;
2387 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002388 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2389 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002390 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002391 }
2392#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002393 return 1;
2394}
2395
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002396static int
2397trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002398{
2399 int sys_res;
2400 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002401 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002402 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002403
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002404 /* Measure the exit time as early as possible to avoid errors. */
2405 if (dtime || cflag)
2406 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002407
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002408 /* BTW, why we don't just memorize syscall no. on entry
2409 * in tcp->something?
2410 */
2411 scno_good = res = get_scno(tcp);
2412 if (res == 0)
2413 return res;
2414 if (res == 1)
2415 res = syscall_fixup(tcp);
2416 if (res == 0)
2417 return res;
2418 if (res == 1)
2419 res = get_error(tcp);
2420 if (res == 0)
2421 return res;
2422 if (res == 1)
2423 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002424
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002425 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
2426 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002427 tcp->flags &= ~TCB_INSYSCALL;
2428 return 0;
2429 }
2430
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002431 if (tcp->flags & TCB_REPRINT) {
2432 printleader(tcp);
2433 tprintf("<... ");
2434 if (scno_good != 1)
2435 tprintf("????");
2436 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2437 tprintf("syscall_%lu", tcp->scno);
2438 else
2439 tprintf("%s", sysent[tcp->scno].sys_name);
2440 tprintf(" resumed> ");
2441 }
2442
2443 if (cflag) {
2444 struct timeval t = tv;
2445 int rc = count_syscall(tcp, &t);
2446 if (cflag == CFLAG_ONLY_STATS)
2447 {
2448 tcp->flags &= ~TCB_INSYSCALL;
2449 return rc;
2450 }
2451 }
2452
2453 if (res != 1) {
2454 tprintf(") ");
2455 tabto(acolumn);
2456 tprintf("= ? <unavailable>");
2457 printtrailer();
2458 tcp->flags &= ~TCB_INSYSCALL;
2459 return res;
2460 }
2461
2462 if (tcp->scno >= nsyscalls || tcp->scno < 0
2463 || (qual_flags[tcp->scno] & QUAL_RAW))
2464 sys_res = printargs(tcp);
2465 else {
2466 if (not_failing_only && tcp->u_error)
2467 return 0; /* ignore failed syscalls */
2468 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2469 }
2470
2471 u_error = tcp->u_error;
2472 tprintf(") ");
2473 tabto(acolumn);
2474 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2475 qual_flags[tcp->scno] & QUAL_RAW) {
2476 if (u_error)
2477 tprintf("= -1 (errno %ld)", u_error);
2478 else
2479 tprintf("= %#lx", tcp->u_rval);
2480 }
2481 else if (!(sys_res & RVAL_NONE) && u_error) {
2482 switch (u_error) {
2483#ifdef LINUX
2484 case ERESTARTSYS:
2485 tprintf("= ? ERESTARTSYS (To be restarted)");
2486 break;
2487 case ERESTARTNOINTR:
2488 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2489 break;
2490 case ERESTARTNOHAND:
2491 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2492 break;
2493 case ERESTART_RESTARTBLOCK:
2494 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2495 break;
2496#endif /* LINUX */
2497 default:
2498 tprintf("= -1 ");
2499 if (u_error < 0)
2500 tprintf("E??? (errno %ld)", u_error);
2501 else if (u_error < nerrnos)
2502 tprintf("%s (%s)", errnoent[u_error],
2503 strerror(u_error));
2504 else
2505 tprintf("ERRNO_%ld (%s)", u_error,
2506 strerror(u_error));
2507 break;
2508 }
2509 if ((sys_res & RVAL_STR) && tcp->auxstr)
2510 tprintf(" (%s)", tcp->auxstr);
2511 }
2512 else {
2513 if (sys_res & RVAL_NONE)
2514 tprintf("= ?");
2515 else {
2516 switch (sys_res & RVAL_MASK) {
2517 case RVAL_HEX:
2518 tprintf("= %#lx", tcp->u_rval);
2519 break;
2520 case RVAL_OCTAL:
2521 tprintf("= %#lo", tcp->u_rval);
2522 break;
2523 case RVAL_UDECIMAL:
2524 tprintf("= %lu", tcp->u_rval);
2525 break;
2526 case RVAL_DECIMAL:
2527 tprintf("= %ld", tcp->u_rval);
2528 break;
2529#ifdef HAVE_LONG_LONG
2530 case RVAL_LHEX:
2531 tprintf("= %#llx", tcp->u_lrval);
2532 break;
2533 case RVAL_LOCTAL:
2534 tprintf("= %#llo", tcp->u_lrval);
2535 break;
2536 case RVAL_LUDECIMAL:
2537 tprintf("= %llu", tcp->u_lrval);
2538 break;
2539 case RVAL_LDECIMAL:
2540 tprintf("= %lld", tcp->u_lrval);
2541 break;
2542#endif
2543 default:
2544 fprintf(stderr,
2545 "invalid rval format\n");
2546 break;
2547 }
2548 }
2549 if ((sys_res & RVAL_STR) && tcp->auxstr)
2550 tprintf(" (%s)", tcp->auxstr);
2551 }
2552 if (dtime) {
2553 tv_sub(&tv, &tv, &tcp->etime);
2554 tprintf(" <%ld.%06ld>",
2555 (long) tv.tv_sec, (long) tv.tv_usec);
2556 }
2557 printtrailer();
2558
2559 dumpio(tcp);
2560 if (fflush(tcp->outf) == EOF)
2561 return -1;
2562 tcp->flags &= ~TCB_INSYSCALL;
2563 return 0;
2564}
2565
2566static int
2567trace_syscall_entering(struct tcb *tcp)
2568{
2569 int sys_res;
2570 int res, scno_good;
2571
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002572 scno_good = res = get_scno(tcp);
2573 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002574 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002575 if (res == 1)
2576 res = syscall_fixup(tcp);
2577 if (res == 0)
2578 return res;
2579 if (res == 1)
2580 res = syscall_enter(tcp);
2581 if (res == 0)
2582 return res;
2583
2584 if (res != 1) {
2585 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002586 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002587 tcp_last = tcp;
2588 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002589 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002590 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2591 tprintf("syscall_%lu(", tcp->scno);
2592 else
2593 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002594 /*
2595 * " <unavailable>" will be added later by the code which
2596 * detects ptrace errors.
2597 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002598 tcp->flags |= TCB_INSYSCALL;
2599 return res;
2600 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002601
Roland McGrath17352792005-06-07 23:21:26 +00002602 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002603#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002604 case SYS_socketcall:
2605 decode_subcall(tcp, SYS_socket_subcall,
2606 SYS_socket_nsubcalls, deref_style);
2607 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002608#endif
2609#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610 case SYS_ipc:
2611 decode_subcall(tcp, SYS_ipc_subcall,
2612 SYS_ipc_nsubcalls, shift_style);
2613 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002614#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615#ifdef SVR4
2616#ifdef SYS_pgrpsys_subcall
2617 case SYS_pgrpsys:
2618 decode_subcall(tcp, SYS_pgrpsys_subcall,
2619 SYS_pgrpsys_nsubcalls, shift_style);
2620 break;
2621#endif /* SYS_pgrpsys_subcall */
2622#ifdef SYS_sigcall_subcall
2623 case SYS_sigcall:
2624 decode_subcall(tcp, SYS_sigcall_subcall,
2625 SYS_sigcall_nsubcalls, mask_style);
2626 break;
2627#endif /* SYS_sigcall_subcall */
2628 case SYS_msgsys:
2629 decode_subcall(tcp, SYS_msgsys_subcall,
2630 SYS_msgsys_nsubcalls, shift_style);
2631 break;
2632 case SYS_shmsys:
2633 decode_subcall(tcp, SYS_shmsys_subcall,
2634 SYS_shmsys_nsubcalls, shift_style);
2635 break;
2636 case SYS_semsys:
2637 decode_subcall(tcp, SYS_semsys_subcall,
2638 SYS_semsys_nsubcalls, shift_style);
2639 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002640 case SYS_sysfs:
2641 decode_subcall(tcp, SYS_sysfs_subcall,
2642 SYS_sysfs_nsubcalls, shift_style);
2643 break;
2644 case SYS_spcall:
2645 decode_subcall(tcp, SYS_spcall_subcall,
2646 SYS_spcall_nsubcalls, shift_style);
2647 break;
2648#ifdef SYS_context_subcall
2649 case SYS_context:
2650 decode_subcall(tcp, SYS_context_subcall,
2651 SYS_context_nsubcalls, shift_style);
2652 break;
2653#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002654#ifdef SYS_door_subcall
2655 case SYS_door:
2656 decode_subcall(tcp, SYS_door_subcall,
2657 SYS_door_nsubcalls, door_style);
2658 break;
2659#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002660#ifdef SYS_kaio_subcall
2661 case SYS_kaio:
2662 decode_subcall(tcp, SYS_kaio_subcall,
2663 SYS_kaio_nsubcalls, shift_style);
2664 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002665#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002666#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002667#ifdef FREEBSD
2668 case SYS_msgsys:
2669 case SYS_shmsys:
2670 case SYS_semsys:
2671 decode_subcall(tcp, 0, 0, table_style);
2672 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002673#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674#ifdef SUNOS4
2675 case SYS_semsys:
2676 decode_subcall(tcp, SYS_semsys_subcall,
2677 SYS_semsys_nsubcalls, shift_style);
2678 break;
2679 case SYS_msgsys:
2680 decode_subcall(tcp, SYS_msgsys_subcall,
2681 SYS_msgsys_nsubcalls, shift_style);
2682 break;
2683 case SYS_shmsys:
2684 decode_subcall(tcp, SYS_shmsys_subcall,
2685 SYS_shmsys_nsubcalls, shift_style);
2686 break;
2687#endif
2688 }
2689
2690 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002691 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692 tcp->flags |= TCB_INSYSCALL;
2693 return 0;
2694 }
2695
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002696 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002698 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 return 0;
2700 }
2701
2702 printleader(tcp);
2703 tcp->flags &= ~TCB_REPRINT;
2704 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002705 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002706 tprintf("syscall_%lu(", tcp->scno);
2707 else
2708 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002709 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2711 sys_res = printargs(tcp);
2712 else
2713 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2714 if (fflush(tcp->outf) == EOF)
2715 return -1;
2716 tcp->flags |= TCB_INSYSCALL;
2717 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002718 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002719 gettimeofday(&tcp->etime, NULL);
2720 return sys_res;
2721}
2722
2723int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002724trace_syscall(struct tcb *tcp)
2725{
2726 return exiting(tcp) ?
2727 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2728}
2729
2730int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002731printargs(tcp)
2732struct tcb *tcp;
2733{
2734 if (entering(tcp)) {
2735 int i;
2736
2737 for (i = 0; i < tcp->u_nargs; i++)
2738 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2739 }
2740 return 0;
2741}
2742
2743long
2744getrval2(tcp)
2745struct tcb *tcp;
2746{
2747 long val = -1;
2748
2749#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002750#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002751 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002752 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002754 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002755#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002756 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002757 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002758#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002759 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002760 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002761#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002762#endif /* LINUX */
2763
2764#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002765 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766 return -1;
2767#endif /* SUNOS4 */
2768
2769#ifdef SVR4
2770#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002771 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002772#endif /* SPARC */
2773#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002774 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002775#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002776#ifdef X86_64
2777 val = tcp->status.PR_REG[RDX];
2778#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002779#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002780 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002781#endif /* MIPS */
2782#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002783
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002784#ifdef FREEBSD
2785 struct reg regs;
2786 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2787 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002788#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002789 return val;
2790}
2791
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002792#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002793/*
2794 * Apparently, indirect system calls have already be converted by ptrace(2),
2795 * so if you see "indir" this program has gone astray.
2796 */
2797int
2798sys_indir(tcp)
2799struct tcb *tcp;
2800{
2801 int i, scno, nargs;
2802
2803 if (entering(tcp)) {
2804 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2805 fprintf(stderr, "Bogus syscall: %u\n", scno);
2806 return 0;
2807 }
2808 nargs = sysent[scno].nargs;
2809 tprintf("%s", sysent[scno].sys_name);
2810 for (i = 0; i < nargs; i++)
2811 tprintf(", %#lx", tcp->u_arg[i+1]);
2812 }
2813 return 0;
2814}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002815#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002816
2817int
2818is_restart_error(struct tcb *tcp)
2819{
2820#ifdef LINUX
2821 if (!syserror(tcp))
2822 return 0;
2823 switch (tcp->u_error) {
2824 case ERESTARTSYS:
2825 case ERESTARTNOINTR:
2826 case ERESTARTNOHAND:
2827 case ERESTART_RESTARTBLOCK:
2828 return 1;
2829 default:
2830 break;
2831 }
2832#endif /* LINUX */
2833 return 0;
2834}