blob: ba2185c804bfb96095d8389e36d6d79c87b805c7 [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 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000886# elif defined(AVR32)
887 /*
888 * Read complete register set in one go.
889 */
890 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
891 return -1;
892
893 /*
894 * We only need to grab the syscall number on syscall entry.
895 */
896 if (!(tcp->flags & TCB_INSYSCALL)) {
897 scno = regs.r8;
898
899 /* Check if we return from execve. */
900 if (tcp->flags & TCB_WAITEXECVE) {
901 tcp->flags &= ~TCB_WAITEXECVE;
902 return 0;
903 }
904 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000905# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000906 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000907 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000908# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000909 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000911# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000912 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000913 return -1;
914
Roland McGrath761b5d72002-12-15 23:58:31 +0000915 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000916 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000918 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000919
920 /* Check CS register value. On x86-64 linux it is:
921 * 0x33 for long mode (64 bit)
922 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000923 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 * to be cached.
925 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000926 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000928 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 case 0x23: currpers = 1; break;
930 case 0x33: currpers = 0; break;
931 default:
932 fprintf(stderr, "Unknown value CS=0x%02X while "
933 "detecting personality of process "
934 "PID=%d\n", (int)val, pid);
935 currpers = current_personality;
936 break;
937 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000938# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 /* This version analyzes the opcode of a syscall instruction.
940 * (int 0x80 on i386 vs. syscall on x86-64)
941 * It works, but is too complicated.
942 */
943 unsigned long val, rip, i;
944
Denys Vlasenko8236f252009-01-02 18:10:08 +0000945 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000947
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 errno = 0;
951
Denys Vlasenko8236f252009-01-02 18:10:08 +0000952 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 if (errno)
954 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000956 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000963 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
966 "PID=%d\n", (int)call, pid);
967 break;
968 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000969# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 if (currpers != current_personality) {
971 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 pid, names[current_personality]);
975 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000978# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700979 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000980 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981 if (!(tcp->flags & TCB_INSYSCALL)) {
982 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000983 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 return -1;
985 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700986 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 return -1;
988 }
Roland McGrathba954762003-03-05 06:29:06 +0000989 /* Check if we return from execve. */
990 if (tcp->flags & TCB_WAITEXECVE) {
991 tcp->flags &= ~TCB_WAITEXECVE;
992 return 0;
993 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000994 } else {
995 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700996 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000997 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 return -1;
1000 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001001# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001002 /*
1003 * Read complete register set in one go.
1004 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001005 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001006 return -1;
1007
1008 /*
1009 * We only need to grab the syscall number on syscall entry.
1010 */
1011 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001012 if (!(tcp->flags & TCB_INSYSCALL)) {
1013 /* Check if we return from execve. */
1014 if (tcp->flags & TCB_WAITEXECVE) {
1015 tcp->flags &= ~TCB_WAITEXECVE;
1016 return 0;
1017 }
1018 }
1019
Roland McGrath0f87c492003-06-03 23:29:04 +00001020 /*
1021 * Note: we only deal with only 32-bit CPUs here.
1022 */
1023 if (regs.ARM_cpsr & 0x20) {
1024 /*
1025 * Get the Thumb-mode system call number
1026 */
1027 scno = regs.ARM_r7;
1028 } else {
1029 /*
1030 * Get the ARM-mode system call number
1031 */
1032 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001033 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001034 if (errno)
1035 return -1;
1036
1037 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1038 tcp->flags &= ~TCB_WAITEXECVE;
1039 return 0;
1040 }
1041
Roland McGrathf691bd22006-04-25 07:34:41 +00001042 /* Handle the EABI syscall convention. We do not
1043 bother converting structures between the two
1044 ABIs, but basic functionality should work even
1045 if strace and the traced program have different
1046 ABIs. */
1047 if (scno == 0xef000000) {
1048 scno = regs.ARM_r7;
1049 } else {
1050 if ((scno & 0x0ff00000) != 0x0f900000) {
1051 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1052 scno);
1053 return -1;
1054 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001055
Roland McGrathf691bd22006-04-25 07:34:41 +00001056 /*
1057 * Fixup the syscall number
1058 */
1059 scno &= 0x000fffff;
1060 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001061 }
Roland McGrath56703312008-05-20 01:35:55 +00001062 if (scno & 0x0f0000) {
1063 /*
1064 * Handle ARM specific syscall
1065 */
1066 set_personality(1);
1067 scno &= 0x0000ffff;
1068 } else
1069 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001070
1071 if (tcp->flags & TCB_INSYSCALL) {
1072 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1073 tcp->flags &= ~TCB_INSYSCALL;
1074 }
1075 } else {
1076 if (!(tcp->flags & TCB_INSYSCALL)) {
1077 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1078 tcp->flags |= TCB_INSYSCALL;
1079 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001081# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001082 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001084# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001085 unsigned long long regs[38];
1086
Roland McGratheb9e2e82009-06-02 16:49:22 -07001087 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001088 return -1;
1089 a3 = regs[REG_A3];
1090 r2 = regs[REG_V0];
1091
1092 if(!(tcp->flags & TCB_INSYSCALL)) {
1093 scno = r2;
1094
1095 /* Check if we return from execve. */
1096 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1097 tcp->flags &= ~TCB_WAITEXECVE;
1098 return 0;
1099 }
1100
1101 if (scno < 0 || scno > nsyscalls) {
1102 if(a3 == 0 || a3 == -1) {
1103 if(debug)
1104 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1105 return 0;
1106 }
1107 }
1108 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001109# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001110 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001111 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001112 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001113 if (upeek(tcp, REG_V0, &scno) < 0)
1114 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001115
Roland McGrath542c2c62008-05-20 01:11:56 +00001116 /* Check if we return from execve. */
1117 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1118 tcp->flags &= ~TCB_WAITEXECVE;
1119 return 0;
1120 }
1121
Wichert Akkermanf90da011999-10-31 21:15:38 +00001122 if (scno < 0 || scno > nsyscalls) {
1123 if(a3 == 0 || a3 == -1) {
1124 if(debug)
1125 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1126 return 0;
1127 }
1128 }
1129 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001130 if (upeek(tcp, REG_V0, &r2) < 0)
1131 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001133# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 return -1;
1136
1137 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001138 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 return -1;
1140
1141 /* Check if we return from execve. */
1142 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1143 tcp->flags &= ~TCB_WAITEXECVE;
1144 return 0;
1145 }
1146
1147 /*
1148 * Do some sanity checks to figure out if it's
1149 * really a syscall entry
1150 */
1151 if (scno < 0 || scno > nsyscalls) {
1152 if (a3 == 0 || a3 == -1) {
1153 if (debug)
1154 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1155 return 0;
1156 }
1157 }
1158 }
1159 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return -1;
1162 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001163# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001165 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 return -1;
1167
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 if (!(tcp->flags & TCB_INSYSCALL)) {
1170 /* Retrieve the syscall trap instruction. */
1171 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001172# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001173 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001174 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001175# else
1176 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001177# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 if (errno)
1179 return -1;
1180
1181 /* Disassemble the trap to see what personality to use. */
1182 switch (trap) {
1183 case 0x91d02010:
1184 /* Linux/SPARC syscall trap. */
1185 set_personality(0);
1186 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001187 case 0x91d0206d:
1188 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001189 set_personality(2);
1190 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 case 0x91d02000:
1192 /* SunOS syscall trap. (pers 1) */
1193 fprintf(stderr,"syscall: SunOS no support\n");
1194 return -1;
1195 case 0x91d02008:
1196 /* Solaris 2.x syscall trap. (per 2) */
1197 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001198 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199 case 0x91d02009:
1200 /* NetBSD/FreeBSD syscall trap. */
1201 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1202 return -1;
1203 case 0x91d02027:
1204 /* Solaris 2.x gettimeofday */
1205 set_personality(1);
1206 break;
1207 default:
1208 /* Unknown syscall trap. */
1209 if(tcp->flags & TCB_WAITEXECVE) {
1210 tcp->flags &= ~TCB_WAITEXECVE;
1211 return 0;
1212 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001213# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001214 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001215# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001216 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 return -1;
1219 }
1220
1221 /* Extract the system call number from the registers. */
1222 if (trap == 0x91d02027)
1223 scno = 156;
1224 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001225 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001227 scno = regs.u_regs[U_REG_O0];
1228 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 +00001229 }
1230 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001231# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001232 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001233 return -1;
1234 if (!(tcp->flags & TCB_INSYSCALL)) {
1235 /* Check if we return from execve. */
1236 if ((tcp->flags & TCB_WAITEXECVE)) {
1237 tcp->flags &= ~TCB_WAITEXECVE;
1238 return 0;
1239 }
1240 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001241# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001242 /*
1243 * In the new syscall ABI, the system call number is in R3.
1244 */
1245 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1246 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001247
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001248 if (scno < 0) {
1249 /* Odd as it may seem, a glibc bug has been known to cause
1250 glibc to issue bogus negative syscall numbers. So for
1251 our purposes, make strace print what it *should* have been */
1252 long correct_scno = (scno & 0xff);
1253 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001254 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001255 "Detected glibc bug: bogus system call"
1256 " number = %ld, correcting to %ld\n",
1257 scno,
1258 correct_scno);
1259 scno = correct_scno;
1260 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001261
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001262 if (!(tcp->flags & TCB_INSYSCALL)) {
1263 /* Check if we return from execve. */
1264 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1265 tcp->flags &= ~TCB_WAITEXECVE;
1266 return 0;
1267 }
1268 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001269# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001270 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001271 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001272 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001273
1274 if (!(tcp->flags & TCB_INSYSCALL)) {
1275 /* Check if we return from execve. */
1276 if (tcp->flags & TCB_WAITEXECVE) {
1277 tcp->flags &= ~TCB_WAITEXECVE;
1278 return 0;
1279 }
1280 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001281# elif defined(CRISV10) || defined(CRISV32)
1282 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1283 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001284# elif defined(TILE)
1285 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1286 return -1;
1287
1288 if (!(tcp->flags & TCB_INSYSCALL)) {
1289 /* Check if we return from execve. */
1290 if (tcp->flags & TCB_WAITEXECVE) {
1291 tcp->flags &= ~TCB_WAITEXECVE;
1292 return 0;
1293 }
1294 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001295# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001297
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001299 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001301#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 /* new syscall ABI returns result in R0 */
1303 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1304 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001305#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001306 /* ABI defines result returned in r9 */
1307 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1308 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001310
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001311#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001312# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001313 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001314# else
1315# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001316 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001317# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001318 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001319 perror("pread");
1320 return -1;
1321 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001322 switch (regs.r_eax) {
1323 case SYS_syscall:
1324 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001325 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1326 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001327 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001328 scno = regs.r_eax;
1329 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001330 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001331# endif /* FREEBSD */
1332# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001333#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001334
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001335 if (!(tcp->flags & TCB_INSYSCALL))
1336 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001337 return 1;
1338}
1339
Pavel Machek4dc3b142000-02-01 17:58:41 +00001340
Roland McGrath17352792005-06-07 23:21:26 +00001341long
1342known_scno(tcp)
1343struct tcb *tcp;
1344{
1345 long scno = tcp->scno;
1346 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1347 scno = sysent[scno].native_scno;
1348 else
1349 scno += NR_SYSCALL_BASE;
1350 return scno;
1351}
1352
Roland McGratheb9e2e82009-06-02 16:49:22 -07001353/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001354 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001355 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1356 * 1: ok, continue in trace_syscall().
1357 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001358 * ("????" etc) and bail out.
1359 */
Roland McGratha4d48532005-06-08 20:45:28 +00001360static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001361syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001362{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001363#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001364 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001365
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001367 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 if (
1369 scno == SYS_fork
1370#ifdef SYS_vfork
1371 || scno == SYS_vfork
1372#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001373#ifdef SYS_fork1
1374 || scno == SYS_fork1
1375#endif /* SYS_fork1 */
1376#ifdef SYS_forkall
1377 || scno == SYS_forkall
1378#endif /* SYS_forkall */
1379#ifdef SYS_rfork1
1380 || scno == SYS_rfork1
1381#endif /* SYS_fork1 */
1382#ifdef SYS_rforkall
1383 || scno == SYS_rforkall
1384#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001385 ) {
1386 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001387 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001389 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 }
1391 else {
1392 fprintf(stderr, "syscall: missing entry\n");
1393 tcp->flags |= TCB_INSYSCALL;
1394 }
1395 }
1396 }
1397 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001398 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399 fprintf(stderr, "syscall: missing exit\n");
1400 tcp->flags &= ~TCB_INSYSCALL;
1401 }
1402 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001403#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001404#ifdef SUNOS4
1405 if (!(tcp->flags & TCB_INSYSCALL)) {
1406 if (scno == 0) {
1407 fprintf(stderr, "syscall: missing entry\n");
1408 tcp->flags |= TCB_INSYSCALL;
1409 }
1410 }
1411 else {
1412 if (scno != 0) {
1413 if (debug) {
1414 /*
1415 * This happens when a signal handler
1416 * for a signal which interrupted a
1417 * a system call makes another system call.
1418 */
1419 fprintf(stderr, "syscall: missing exit\n");
1420 }
1421 tcp->flags &= ~TCB_INSYSCALL;
1422 }
1423 }
1424#endif /* SUNOS4 */
1425#ifdef LINUX
1426#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001427 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 return -1;
1429 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1430 if (debug)
1431 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1432 return 0;
1433 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001434#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001435 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001436 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001437 if (current_personality == 1)
1438 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001439 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1440 if (debug)
1441 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1442 return 0;
1443 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001444#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001445 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001446 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001447 if (syscall_mode != -ENOSYS)
1448 syscall_mode = tcp->scno;
1449 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001450 if (debug)
1451 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1452 return 0;
1453 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001454 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1455 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1456 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1457 /*
1458 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1459 * flag set for the post-execve SIGTRAP to see and reset.
1460 */
1461 gpr2 = 0;
1462 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463#elif defined (POWERPC)
1464# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001465 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001466 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001467 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001468 return -1;
1469 if (flags & SO_MASK)
1470 result = -result;
1471#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001472 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473 return -1;
1474 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1475 if (debug)
1476 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1477 return 0;
1478 }
1479#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001480 /*
1481 * Nothing required
1482 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001483#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001484 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001485 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001486#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001487 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001488 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001489#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001490 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001491 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001492 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001493 return -1;
1494 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1495 if (debug)
1496 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1497 return 0;
1498 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001499#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001500 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001501 return -1;
1502 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1503 if (debug)
1504 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1505 return 0;
1506 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507#endif
1508#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001509 return 1;
1510}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001511
Roland McGrathc1e45922008-05-27 23:18:29 +00001512#ifdef LINUX
1513/*
1514 * Check the syscall return value register value for whether it is
1515 * a negated errno code indicating an error, or a success return value.
1516 */
1517static inline int
1518is_negated_errno(unsigned long int val)
1519{
1520 unsigned long int max = -(long int) nerrnos;
1521 if (personality_wordsize[current_personality] < sizeof(val)) {
1522 val = (unsigned int) val;
1523 max = (unsigned int) max;
1524 }
1525 return val > max;
1526}
1527#endif
1528
Roland McGratha4d48532005-06-08 20:45:28 +00001529static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001530get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001531{
1532 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001534# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001535 if (is_negated_errno(gpr2)) {
1536 tcp->u_rval = -1;
1537 u_error = -gpr2;
1538 }
1539 else {
1540 tcp->u_rval = gpr2;
1541 u_error = 0;
1542 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001543# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 if (is_negated_errno(eax)) {
1545 tcp->u_rval = -1;
1546 u_error = -eax;
1547 }
1548 else {
1549 tcp->u_rval = eax;
1550 u_error = 0;
1551 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001552# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001553 if (is_negated_errno(rax)) {
1554 tcp->u_rval = -1;
1555 u_error = -rax;
1556 }
1557 else {
1558 tcp->u_rval = rax;
1559 u_error = 0;
1560 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001561# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001562 if (ia32) {
1563 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001564
Roland McGrathc1e45922008-05-27 23:18:29 +00001565 err = (int)r8;
1566 if (is_negated_errno(err)) {
1567 tcp->u_rval = -1;
1568 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001569 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001570 else {
1571 tcp->u_rval = err;
1572 u_error = 0;
1573 }
1574 } else {
1575 if (r10) {
1576 tcp->u_rval = -1;
1577 u_error = r8;
1578 } else {
1579 tcp->u_rval = r8;
1580 u_error = 0;
1581 }
1582 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001583# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001584 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001585 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001586 u_error = r2;
1587 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001588 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001589 u_error = 0;
1590 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001591# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001592 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593 tcp->u_rval = -1;
1594 u_error = -result;
1595 }
1596 else {
1597 tcp->u_rval = result;
1598 u_error = 0;
1599 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001600# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001601 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 tcp->u_rval = -1;
1603 u_error = -d0;
1604 }
1605 else {
1606 tcp->u_rval = d0;
1607 u_error = 0;
1608 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001609# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001610 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001612 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 }
1614 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001615 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 u_error = 0;
1617 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001618# elif defined(AVR32)
1619 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1620 tcp->u_rval = -1;
1621 u_error = -regs.r12;
1622 }
1623 else {
1624 tcp->u_rval = regs.r12;
1625 u_error = 0;
1626 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001627# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001628 if (is_negated_errno(r0)) {
1629 tcp->u_rval = -1;
1630 u_error = -r0;
1631 } else {
1632 tcp->u_rval = r0;
1633 u_error = 0;
1634 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001635# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 if (a3) {
1637 tcp->u_rval = -1;
1638 u_error = r0;
1639 }
1640 else {
1641 tcp->u_rval = r0;
1642 u_error = 0;
1643 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001644# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001645 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001647 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 }
1649 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001650 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651 u_error = 0;
1652 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001653# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001654 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001655 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001656 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001657 }
1658 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001659 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001660 u_error = 0;
1661 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001662# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001663 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001664 tcp->u_rval = -1;
1665 u_error = -r28;
1666 }
1667 else {
1668 tcp->u_rval = r28;
1669 u_error = 0;
1670 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001671# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001672 /* interpret R0 as return value or error number */
1673 if (is_negated_errno(r0)) {
1674 tcp->u_rval = -1;
1675 u_error = -r0;
1676 }
1677 else {
1678 tcp->u_rval = r0;
1679 u_error = 0;
1680 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001681# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001682 /* interpret result as return value or error number */
1683 if (is_negated_errno(r9)) {
1684 tcp->u_rval = -1;
1685 u_error = -r9;
1686 }
1687 else {
1688 tcp->u_rval = r9;
1689 u_error = 0;
1690 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001691# elif defined(CRISV10) || defined(CRISV32)
1692 if (r10 && (unsigned) -r10 < nerrnos) {
1693 tcp->u_rval = -1;
1694 u_error = -r10;
1695 }
1696 else {
1697 tcp->u_rval = r10;
1698 u_error = 0;
1699 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001700# elif defined(TILE)
1701 long rval;
1702 /* interpret result as return value or error number */
1703 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1704 return -1;
1705 if (rval < 0 && rval > -nerrnos) {
1706 tcp->u_rval = -1;
1707 u_error = -rval;
1708 }
1709 else {
1710 tcp->u_rval = rval;
1711 u_error = 0;
1712 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001713# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714#endif /* LINUX */
1715#ifdef SUNOS4
1716 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001717 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 return -1;
1719 u_error >>= 24; /* u_error is a char */
1720
1721 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001722 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001723 return -1;
1724#endif /* SUNOS4 */
1725#ifdef SVR4
1726#ifdef SPARC
1727 /* Judicious guessing goes a long way. */
1728 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1729 tcp->u_rval = -1;
1730 u_error = tcp->status.pr_reg[R_O0];
1731 }
1732 else {
1733 tcp->u_rval = tcp->status.pr_reg[R_O0];
1734 u_error = 0;
1735 }
1736#endif /* SPARC */
1737#ifdef I386
1738 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001739 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001741 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742 }
1743 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001744 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001745#ifdef HAVE_LONG_LONG
1746 tcp->u_lrval =
1747 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1748 tcp->status.PR_REG[EAX];
1749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750 u_error = 0;
1751 }
1752#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001753#ifdef X86_64
1754 /* Wanna know how to kill an hour single-stepping? */
1755 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1756 tcp->u_rval = -1;
1757 u_error = tcp->status.PR_REG[RAX];
1758 }
1759 else {
1760 tcp->u_rval = tcp->status.PR_REG[RAX];
1761 u_error = 0;
1762 }
1763#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764#ifdef MIPS
1765 if (tcp->status.pr_reg[CTX_A3]) {
1766 tcp->u_rval = -1;
1767 u_error = tcp->status.pr_reg[CTX_V0];
1768 }
1769 else {
1770 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1771 u_error = 0;
1772 }
1773#endif /* MIPS */
1774#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001775#ifdef FREEBSD
1776 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001777 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001778 u_error = regs.r_eax;
1779 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001780 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001781 tcp->u_lrval =
1782 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1783 u_error = 0;
1784 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001785#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001786 tcp->u_error = u_error;
1787 return 1;
1788}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789
Roland McGrathb69f81b2002-12-21 23:25:18 +00001790int
1791force_result(tcp, error, rval)
1792 struct tcb *tcp;
1793 int error;
1794 long rval;
1795{
1796#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001797# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001798 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001799 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1800 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001801# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001802 eax = error ? -error : rval;
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1804 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001805# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001806 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001808 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001809# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001810 if (ia32) {
1811 r8 = error ? -error : rval;
1812 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1813 return -1;
1814 }
1815 else {
1816 if (error) {
1817 r8 = error;
1818 r10 = -1;
1819 }
1820 else {
1821 r8 = rval;
1822 r10 = 0;
1823 }
1824 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1825 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1826 return -1;
1827 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001828# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001829 r0 = error ? -error : rval;
1830 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1831 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001832# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 if (error) {
1834 r2 = error;
1835 a3 = -1;
1836 }
1837 else {
1838 r2 = rval;
1839 a3 = 0;
1840 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001841 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001842 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1843 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001844 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001845# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001846 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 return -1;
1848 if (error) {
1849 flags |= SO_MASK;
1850 result = error;
1851 }
1852 else {
1853 flags &= ~SO_MASK;
1854 result = rval;
1855 }
Roland McGratheb285352003-01-14 09:59:00 +00001856 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1857 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001858 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001859# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001860 d0 = error ? -error : rval;
1861 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1862 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001863# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001864 regs.ARM_r0 = error ? -error : rval;
1865 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001866 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001867# elif defined(AVR32)
1868 regs.r12 = error ? -error : rval;
1869 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001871# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001872 if (error) {
1873 a3 = -1;
1874 r0 = error;
1875 }
1876 else {
1877 a3 = 0;
1878 r0 = rval;
1879 }
1880 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1881 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1882 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001883# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001884 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1885 return -1;
1886 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001887 regs.psr |= PSR_C;
1888 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001889 }
1890 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001891 regs.psr &= ~PSR_C;
1892 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001893 }
1894 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1895 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001896# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001897 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1898 return -1;
1899 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001900 regs.tstate |= 0x1100000000UL;
1901 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001902 }
1903 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001904 regs.tstate &= ~0x1100000000UL;
1905 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001906 }
1907 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1908 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001910 r28 = error ? -error : rval;
1911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001913# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914 r0 = error ? -error : rval;
1915 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001918 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001919 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1920 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001921# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001923
Roland McGrathb69f81b2002-12-21 23:25:18 +00001924#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001925 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1926 error << 24) < 0 ||
1927 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001928 return -1;
1929#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001930
Roland McGrathb69f81b2002-12-21 23:25:18 +00001931#ifdef SVR4
1932 /* XXX no clue */
1933 return -1;
1934#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001935
Roland McGrathb69f81b2002-12-21 23:25:18 +00001936#ifdef FREEBSD
1937 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001938 perror("pread");
1939 return -1;
1940 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001941 if (error) {
1942 regs.r_eflags |= PSL_C;
1943 regs.r_eax = error;
1944 }
1945 else {
1946 regs.r_eflags &= ~PSL_C;
1947 regs.r_eax = rval;
1948 }
1949 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001950 perror("pwrite");
1951 return -1;
1952 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001953#endif /* FREEBSD */
1954
1955 /* All branches reach here on success (only). */
1956 tcp->u_error = error;
1957 tcp->u_rval = rval;
1958 return 0;
1959}
1960
Roland McGratha4d48532005-06-08 20:45:28 +00001961static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001962syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001963{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001965#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001966 {
1967 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001968 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1969 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001970 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001971 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001972 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001973 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001974 return -1;
1975 }
1976 }
1977#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001978 {
1979 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001980 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1981 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001982 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001983 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001984 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001985 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1986 * for scno somewhere above here!
1987 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001988 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001989 return -1;
1990 }
1991 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001992#elif defined (IA64)
1993 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001994 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001995 unsigned long *out0, cfm, sof, sol, i;
1996 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001997 /* be backwards compatible with kernel < 2.4.4... */
1998# ifndef PT_RBS_END
1999# define PT_RBS_END PT_AR_BSP
2000# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002001
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002002 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002003 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002004 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002005 return -1;
2006
2007 sof = (cfm >> 0) & 0x7f;
2008 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002009 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002010
2011 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2012 && sysent[tcp->scno].nargs != -1)
2013 tcp->u_nargs = sysent[tcp->scno].nargs;
2014 else
2015 tcp->u_nargs = MAX_ARGS;
2016 for (i = 0; i < tcp->u_nargs; ++i) {
2017 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2018 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2019 return -1;
2020 }
2021 } else {
2022 int i;
2023
2024 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002025 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002026 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002027 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002028 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002029 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002030 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002031 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002032 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002033 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002034 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002035 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002036 return -1;
2037
2038 for (i = 0; i < 6; ++i)
2039 /* truncate away IVE sign-extension */
2040 tcp->u_arg[i] &= 0xffffffff;
2041
2042 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2043 && sysent[tcp->scno].nargs != -1)
2044 tcp->u_nargs = sysent[tcp->scno].nargs;
2045 else
2046 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002047 }
2048 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002049#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2050 /* N32 and N64 both use up to six registers. */
2051 {
2052 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002053 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002054
2055 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2056 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002057 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002058 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002059
David Daney20037042010-02-09 21:22:30 +00002060 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002061 return -1;
2062
Roland McGratheb9e2e82009-06-02 16:49:22 -07002063 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002064 tcp->u_arg[i] = regs[REG_A0 + i];
2065# if defined (LINUX_MIPSN32)
2066 tcp->ext_arg[i] = regs[REG_A0 + i];
2067# endif
2068 }
2069 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002070#elif defined (MIPS)
2071 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002072 long sp;
2073 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002074
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002075 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2076 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002077 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002078 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002079 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002080 if(upeek(tcp, REG_SP, &sp) < 0)
2081 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002082 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002083 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2084 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002085 }
2086 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2087 (char *)(tcp->u_arg + 4));
2088 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002089 for(i = 0; i < nargs; i++) {
2090 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2091 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002092 }
2093 }
2094 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002096# ifndef PT_ORIG_R3
2097# define PT_ORIG_R3 34
2098# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 {
2100 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002101 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2102 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002103 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002104 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002106 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002107 (sizeof(unsigned long)*PT_ORIG_R3) :
2108 ((i+PT_R3)*sizeof(unsigned long)),
2109 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 return -1;
2111 }
2112 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002113#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002115 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002116
2117 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2118 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002119 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002120 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002122 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002124#elif defined (HPPA)
2125 {
2126 int i;
2127
2128 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2129 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002130 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002131 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002132 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002133 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002134 return -1;
2135 }
2136 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002137#elif defined(ARM)
2138 {
2139 int i;
2140
2141 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2142 tcp->u_nargs = sysent[tcp->scno].nargs;
2143 else
2144 tcp->u_nargs = MAX_ARGS;
2145 for (i = 0; i < tcp->u_nargs; i++)
2146 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002147 }
2148#elif defined(AVR32)
2149 tcp->u_nargs = sysent[tcp->scno].nargs;
2150 tcp->u_arg[0] = regs.r12;
2151 tcp->u_arg[1] = regs.r11;
2152 tcp->u_arg[2] = regs.r10;
2153 tcp->u_arg[3] = regs.r9;
2154 tcp->u_arg[4] = regs.r5;
2155 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002156#elif defined(BFIN)
2157 {
2158 int i;
2159 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2160
2161 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2162 tcp->u_nargs = sysent[tcp->scno].nargs;
2163 else
2164 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2165
2166 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002167 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002168 return -1;
2169 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002170#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002171 {
2172 int i;
2173 static int syscall_regs[] = {
2174 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2175 REG_REG0, REG_REG0+1, REG_REG0+2
2176 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002177
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002178 tcp->u_nargs = sysent[tcp->scno].nargs;
2179 for (i = 0; i < tcp->u_nargs; i++) {
2180 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2181 return -1;
2182 }
2183 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002184#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002185 {
2186 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002187 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002188 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2189
2190 /*
2191 * TODO: should also check that the number of arguments encoded
2192 * in the trap number matches the number strace expects.
2193 */
2194 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002195 assert(sysent[tcp->scno].nargs <
2196 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002197 */
2198
2199 tcp->u_nargs = sysent[tcp->scno].nargs;
2200 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002201 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002202 return -1;
2203 }
2204 }
2205
Michal Ludvig0e035502002-09-23 15:41:01 +00002206#elif defined(X86_64)
2207 {
2208 int i;
2209 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2210 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002211 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002212 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002213
Michal Ludvig0e035502002-09-23 15:41:01 +00002214 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2215 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002216 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002217 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002218 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002219 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002220 return -1;
2221 }
2222 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002223#elif defined(CRISV10) || defined(CRISV32)
2224 {
2225 int i;
2226 static const int crisregs[] = {
2227 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2228 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2229 };
2230
2231 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2232 tcp->u_nargs = sysent[tcp->scno].nargs;
2233 else
2234 tcp->u_nargs = 0;
2235 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002236 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002237 return -1;
2238 }
2239 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002240#elif defined(TILE)
2241 {
2242 int i;
2243 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2244 tcp->u_nargs = sysent[tcp->scno].nargs;
2245 else
2246 tcp->u_nargs = MAX_ARGS;
2247 for (i = 0; i < tcp->u_nargs; ++i) {
2248 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2249 return -1;
2250 }
2251 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002252#elif defined (M68K)
2253 {
2254 int i;
2255 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2256 tcp->u_nargs = sysent[tcp->scno].nargs;
2257 else
2258 tcp->u_nargs = MAX_ARGS;
2259 for (i = 0; i < tcp->u_nargs; i++) {
2260 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2261 return -1;
2262 }
2263 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002264#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 {
2266 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2268 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002269 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002270 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002271 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002272 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 return -1;
2274 }
2275 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002276#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277#endif /* LINUX */
2278#ifdef SUNOS4
2279 {
2280 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002281 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2282 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002283 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002284 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285 for (i = 0; i < tcp->u_nargs; i++) {
2286 struct user *u;
2287
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002288 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2290 return -1;
2291 }
2292 }
2293#endif /* SUNOS4 */
2294#ifdef SVR4
2295#ifdef MIPS
2296 /*
2297 * SGI is broken: even though it has pr_sysarg, it doesn't
2298 * set them on system call entry. Get a clue.
2299 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002300 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002301 tcp->u_nargs = sysent[tcp->scno].nargs;
2302 else
2303 tcp->u_nargs = tcp->status.pr_nsysarg;
2304 if (tcp->u_nargs > 4) {
2305 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2306 4*sizeof(tcp->u_arg[0]));
2307 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2308 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2309 }
2310 else {
2311 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2312 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2313 }
John Hughes25299712001-03-06 10:10:06 +00002314#elif UNIXWARE >= 2
2315 /*
2316 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2317 */
2318 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2319 tcp->u_nargs = sysent[tcp->scno].nargs;
2320 else
2321 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2322 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2323 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2324#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002325 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002326 tcp->u_nargs = sysent[tcp->scno].nargs;
2327 else
2328 tcp->u_nargs = tcp->status.pr_nsysarg;
2329 {
2330 int i;
2331 for (i = 0; i < tcp->u_nargs; i++)
2332 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2333 }
John Hughes25299712001-03-06 10:10:06 +00002334#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002335 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002336 tcp->u_nargs = sysent[tcp->scno].nargs;
2337 else
2338 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002339 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002340 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002341#else
2342 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002343#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002344#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002345#ifdef FREEBSD
2346 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2347 sysent[tcp->scno].nargs > tcp->status.val)
2348 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002349 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002350 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 if (tcp->u_nargs < 0)
2352 tcp->u_nargs = 0;
2353 if (tcp->u_nargs > MAX_ARGS)
2354 tcp->u_nargs = MAX_ARGS;
2355 switch(regs.r_eax) {
2356 case SYS___syscall:
2357 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2358 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002359 break;
2360 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2362 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002363 break;
2364 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002365 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2366 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002367 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002368 }
2369#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370 return 1;
2371}
2372
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002373static int
2374trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002375{
2376 int sys_res;
2377 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002378 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002379 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002380
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002381 /* Measure the exit time as early as possible to avoid errors. */
2382 if (dtime || cflag)
2383 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002384
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002385 /* BTW, why we don't just memorize syscall no. on entry
2386 * in tcp->something?
2387 */
2388 scno_good = res = get_scno(tcp);
2389 if (res == 0)
2390 return res;
2391 if (res == 1)
2392 res = syscall_fixup(tcp);
2393 if (res == 0)
2394 return res;
2395 if (res == 1)
2396 res = get_error(tcp);
2397 if (res == 0)
2398 return res;
2399 if (res == 1)
2400 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002401
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002402 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
2403 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404 tcp->flags &= ~TCB_INSYSCALL;
2405 return 0;
2406 }
2407
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002408 if (tcp->flags & TCB_REPRINT) {
2409 printleader(tcp);
2410 tprintf("<... ");
2411 if (scno_good != 1)
2412 tprintf("????");
2413 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2414 tprintf("syscall_%lu", tcp->scno);
2415 else
2416 tprintf("%s", sysent[tcp->scno].sys_name);
2417 tprintf(" resumed> ");
2418 }
2419
2420 if (cflag) {
2421 struct timeval t = tv;
2422 int rc = count_syscall(tcp, &t);
2423 if (cflag == CFLAG_ONLY_STATS)
2424 {
2425 tcp->flags &= ~TCB_INSYSCALL;
2426 return rc;
2427 }
2428 }
2429
2430 if (res != 1) {
2431 tprintf(") ");
2432 tabto(acolumn);
2433 tprintf("= ? <unavailable>");
2434 printtrailer();
2435 tcp->flags &= ~TCB_INSYSCALL;
2436 return res;
2437 }
2438
2439 if (tcp->scno >= nsyscalls || tcp->scno < 0
2440 || (qual_flags[tcp->scno] & QUAL_RAW))
2441 sys_res = printargs(tcp);
2442 else {
2443 if (not_failing_only && tcp->u_error)
2444 return 0; /* ignore failed syscalls */
2445 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2446 }
2447
2448 u_error = tcp->u_error;
2449 tprintf(") ");
2450 tabto(acolumn);
2451 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2452 qual_flags[tcp->scno] & QUAL_RAW) {
2453 if (u_error)
2454 tprintf("= -1 (errno %ld)", u_error);
2455 else
2456 tprintf("= %#lx", tcp->u_rval);
2457 }
2458 else if (!(sys_res & RVAL_NONE) && u_error) {
2459 switch (u_error) {
2460#ifdef LINUX
2461 case ERESTARTSYS:
2462 tprintf("= ? ERESTARTSYS (To be restarted)");
2463 break;
2464 case ERESTARTNOINTR:
2465 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2466 break;
2467 case ERESTARTNOHAND:
2468 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2469 break;
2470 case ERESTART_RESTARTBLOCK:
2471 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2472 break;
2473#endif /* LINUX */
2474 default:
2475 tprintf("= -1 ");
2476 if (u_error < 0)
2477 tprintf("E??? (errno %ld)", u_error);
2478 else if (u_error < nerrnos)
2479 tprintf("%s (%s)", errnoent[u_error],
2480 strerror(u_error));
2481 else
2482 tprintf("ERRNO_%ld (%s)", u_error,
2483 strerror(u_error));
2484 break;
2485 }
2486 if ((sys_res & RVAL_STR) && tcp->auxstr)
2487 tprintf(" (%s)", tcp->auxstr);
2488 }
2489 else {
2490 if (sys_res & RVAL_NONE)
2491 tprintf("= ?");
2492 else {
2493 switch (sys_res & RVAL_MASK) {
2494 case RVAL_HEX:
2495 tprintf("= %#lx", tcp->u_rval);
2496 break;
2497 case RVAL_OCTAL:
2498 tprintf("= %#lo", tcp->u_rval);
2499 break;
2500 case RVAL_UDECIMAL:
2501 tprintf("= %lu", tcp->u_rval);
2502 break;
2503 case RVAL_DECIMAL:
2504 tprintf("= %ld", tcp->u_rval);
2505 break;
2506#ifdef HAVE_LONG_LONG
2507 case RVAL_LHEX:
2508 tprintf("= %#llx", tcp->u_lrval);
2509 break;
2510 case RVAL_LOCTAL:
2511 tprintf("= %#llo", tcp->u_lrval);
2512 break;
2513 case RVAL_LUDECIMAL:
2514 tprintf("= %llu", tcp->u_lrval);
2515 break;
2516 case RVAL_LDECIMAL:
2517 tprintf("= %lld", tcp->u_lrval);
2518 break;
2519#endif
2520 default:
2521 fprintf(stderr,
2522 "invalid rval format\n");
2523 break;
2524 }
2525 }
2526 if ((sys_res & RVAL_STR) && tcp->auxstr)
2527 tprintf(" (%s)", tcp->auxstr);
2528 }
2529 if (dtime) {
2530 tv_sub(&tv, &tv, &tcp->etime);
2531 tprintf(" <%ld.%06ld>",
2532 (long) tv.tv_sec, (long) tv.tv_usec);
2533 }
2534 printtrailer();
2535
2536 dumpio(tcp);
2537 if (fflush(tcp->outf) == EOF)
2538 return -1;
2539 tcp->flags &= ~TCB_INSYSCALL;
2540 return 0;
2541}
2542
2543static int
2544trace_syscall_entering(struct tcb *tcp)
2545{
2546 int sys_res;
2547 int res, scno_good;
2548
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002549 scno_good = res = get_scno(tcp);
2550 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002551 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002552 if (res == 1)
2553 res = syscall_fixup(tcp);
2554 if (res == 0)
2555 return res;
2556 if (res == 1)
2557 res = syscall_enter(tcp);
2558 if (res == 0)
2559 return res;
2560
2561 if (res != 1) {
2562 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002563 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002564 tcp_last = tcp;
2565 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002566 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002567 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2568 tprintf("syscall_%lu(", tcp->scno);
2569 else
2570 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002571 /*
2572 * " <unavailable>" will be added later by the code which
2573 * detects ptrace errors.
2574 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002575 tcp->flags |= TCB_INSYSCALL;
2576 return res;
2577 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002578
Roland McGrath17352792005-06-07 23:21:26 +00002579 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002580#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002581 case SYS_socketcall:
2582 decode_subcall(tcp, SYS_socket_subcall,
2583 SYS_socket_nsubcalls, deref_style);
2584 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002585#endif
2586#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002587 case SYS_ipc:
2588 decode_subcall(tcp, SYS_ipc_subcall,
2589 SYS_ipc_nsubcalls, shift_style);
2590 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002591#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592#ifdef SVR4
2593#ifdef SYS_pgrpsys_subcall
2594 case SYS_pgrpsys:
2595 decode_subcall(tcp, SYS_pgrpsys_subcall,
2596 SYS_pgrpsys_nsubcalls, shift_style);
2597 break;
2598#endif /* SYS_pgrpsys_subcall */
2599#ifdef SYS_sigcall_subcall
2600 case SYS_sigcall:
2601 decode_subcall(tcp, SYS_sigcall_subcall,
2602 SYS_sigcall_nsubcalls, mask_style);
2603 break;
2604#endif /* SYS_sigcall_subcall */
2605 case SYS_msgsys:
2606 decode_subcall(tcp, SYS_msgsys_subcall,
2607 SYS_msgsys_nsubcalls, shift_style);
2608 break;
2609 case SYS_shmsys:
2610 decode_subcall(tcp, SYS_shmsys_subcall,
2611 SYS_shmsys_nsubcalls, shift_style);
2612 break;
2613 case SYS_semsys:
2614 decode_subcall(tcp, SYS_semsys_subcall,
2615 SYS_semsys_nsubcalls, shift_style);
2616 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002617 case SYS_sysfs:
2618 decode_subcall(tcp, SYS_sysfs_subcall,
2619 SYS_sysfs_nsubcalls, shift_style);
2620 break;
2621 case SYS_spcall:
2622 decode_subcall(tcp, SYS_spcall_subcall,
2623 SYS_spcall_nsubcalls, shift_style);
2624 break;
2625#ifdef SYS_context_subcall
2626 case SYS_context:
2627 decode_subcall(tcp, SYS_context_subcall,
2628 SYS_context_nsubcalls, shift_style);
2629 break;
2630#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002631#ifdef SYS_door_subcall
2632 case SYS_door:
2633 decode_subcall(tcp, SYS_door_subcall,
2634 SYS_door_nsubcalls, door_style);
2635 break;
2636#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002637#ifdef SYS_kaio_subcall
2638 case SYS_kaio:
2639 decode_subcall(tcp, SYS_kaio_subcall,
2640 SYS_kaio_nsubcalls, shift_style);
2641 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002642#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002643#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002644#ifdef FREEBSD
2645 case SYS_msgsys:
2646 case SYS_shmsys:
2647 case SYS_semsys:
2648 decode_subcall(tcp, 0, 0, table_style);
2649 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002650#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651#ifdef SUNOS4
2652 case SYS_semsys:
2653 decode_subcall(tcp, SYS_semsys_subcall,
2654 SYS_semsys_nsubcalls, shift_style);
2655 break;
2656 case SYS_msgsys:
2657 decode_subcall(tcp, SYS_msgsys_subcall,
2658 SYS_msgsys_nsubcalls, shift_style);
2659 break;
2660 case SYS_shmsys:
2661 decode_subcall(tcp, SYS_shmsys_subcall,
2662 SYS_shmsys_nsubcalls, shift_style);
2663 break;
2664#endif
2665 }
2666
2667 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002668 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 tcp->flags |= TCB_INSYSCALL;
2670 return 0;
2671 }
2672
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002673 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002675 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002676 return 0;
2677 }
2678
2679 printleader(tcp);
2680 tcp->flags &= ~TCB_REPRINT;
2681 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002682 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683 tprintf("syscall_%lu(", tcp->scno);
2684 else
2685 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002686 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2688 sys_res = printargs(tcp);
2689 else
2690 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2691 if (fflush(tcp->outf) == EOF)
2692 return -1;
2693 tcp->flags |= TCB_INSYSCALL;
2694 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002695 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 gettimeofday(&tcp->etime, NULL);
2697 return sys_res;
2698}
2699
2700int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002701trace_syscall(struct tcb *tcp)
2702{
2703 return exiting(tcp) ?
2704 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2705}
2706
2707int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708printargs(tcp)
2709struct tcb *tcp;
2710{
2711 if (entering(tcp)) {
2712 int i;
2713
2714 for (i = 0; i < tcp->u_nargs; i++)
2715 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2716 }
2717 return 0;
2718}
2719
2720long
2721getrval2(tcp)
2722struct tcb *tcp;
2723{
2724 long val = -1;
2725
2726#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002727#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002728 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002729 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002731 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002732#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002733 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002734 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002735#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002736 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002737 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002738#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002739#endif /* LINUX */
2740
2741#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002742 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743 return -1;
2744#endif /* SUNOS4 */
2745
2746#ifdef SVR4
2747#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002748 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002749#endif /* SPARC */
2750#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002751 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002752#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002753#ifdef X86_64
2754 val = tcp->status.PR_REG[RDX];
2755#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002756#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002757 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758#endif /* MIPS */
2759#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002760
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002761#ifdef FREEBSD
2762 struct reg regs;
2763 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2764 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002765#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766 return val;
2767}
2768
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002769#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002770/*
2771 * Apparently, indirect system calls have already be converted by ptrace(2),
2772 * so if you see "indir" this program has gone astray.
2773 */
2774int
2775sys_indir(tcp)
2776struct tcb *tcp;
2777{
2778 int i, scno, nargs;
2779
2780 if (entering(tcp)) {
2781 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2782 fprintf(stderr, "Bogus syscall: %u\n", scno);
2783 return 0;
2784 }
2785 nargs = sysent[scno].nargs;
2786 tprintf("%s", sysent[scno].sys_name);
2787 for (i = 0; i < nargs; i++)
2788 tprintf(", %#lx", tcp->u_arg[i+1]);
2789 }
2790 return 0;
2791}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002792#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002793
2794int
2795is_restart_error(struct tcb *tcp)
2796{
2797#ifdef LINUX
2798 if (!syserror(tcp))
2799 return 0;
2800 switch (tcp->u_error) {
2801 case ERESTARTSYS:
2802 case ERESTARTNOINTR:
2803 case ERESTARTNOHAND:
2804 case ERESTART_RESTARTBLOCK:
2805 return 1;
2806 default:
2807 break;
2808 }
2809#endif /* LINUX */
2810 return 0;
2811}