blob: c2099a71211188bc6129f2509e8a31081f18da1d [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
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000075#ifdef LINUX
76#ifndef ERESTARTSYS
77#define ERESTARTSYS 512
78#endif
79#ifndef ERESTARTNOINTR
80#define ERESTARTNOINTR 513
81#endif
82#ifndef ERESTARTNOHAND
83#define ERESTARTNOHAND 514 /* restart if no handler.. */
84#endif
85#ifndef ENOIOCTLCMD
86#define ENOIOCTLCMD 515 /* No ioctl command */
87#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000088#ifndef ERESTART_RESTARTBLOCK
89#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
90#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifndef NSIG
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020092#warning: NSIG is not defined, using 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000093#define NSIG 32
94#endif
95#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020096/* Ugh. Is this really correct? ARM has no RT signals?! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000097#undef NSIG
98#define NSIG 32
99#endif
100#endif /* LINUX */
101
102#include "syscall.h"
103
104/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000105#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000106#define TF TRACE_FILE
107#define TI TRACE_IPC
108#define TN TRACE_NETWORK
109#define TP TRACE_PROCESS
110#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000111#define NF SYSCALL_NEVER_FAILS
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200112#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000113
Roland McGrathee36ce12004-09-04 03:53:10 +0000114static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#include "syscallent.h"
116};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117
118#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000119static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120#include "syscallent1.h"
121};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200122#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123
124#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000125static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126#include "syscallent2.h"
127};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200128#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129
130/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000131#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132#undef TF
133#undef TI
134#undef TN
135#undef TP
136#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000137#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200138#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000139
Denys Vlasenko39fca622011-08-20 02:12:33 +0200140
141/*
142 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
143 * program `ioctlsort', such that the list is sorted by the `code' field.
144 * This has the side-effect of resolving the _IO.. macros into
145 * plain integers, eliminating the need to include here everything
146 * in "/usr/include".
147 */
148
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000151#include "errnoent.h"
152};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200153static const char *const signalent0[] = {
154#include "signalent.h"
155};
156static const struct ioctlent ioctlent0[] = {
157#include "ioctlent.h"
158};
159enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
160enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
161enum { nsignals0 = ARRAY_SIZE(signalent0) };
162enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
163int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164
165#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000166static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167#include "errnoent1.h"
168};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200169static const char *const signalent1[] = {
170#include "signalent1.h"
171};
172static const struct ioctlent ioctlent1[] = {
173#include "ioctlent1.h"
174};
175enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
176enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
177enum { nsignals1 = ARRAY_SIZE(signalent1) };
178enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
179int qual_flags1[MAX_QUALS];
180#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000181
182#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000183static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184#include "errnoent2.h"
185};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200186static const char *const signalent2[] = {
187#include "signalent2.h"
188};
189static const struct ioctlent ioctlent2[] = {
190#include "ioctlent2.h"
191};
192enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
193enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
194enum { nsignals2 = ARRAY_SIZE(signalent2) };
195enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
196int qual_flags2[MAX_QUALS];
197#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198
Denys Vlasenko39fca622011-08-20 02:12:33 +0200199
200const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000201const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200202const char *const *signalent;
203const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200204unsigned nsyscalls;
205unsigned nerrnos;
206unsigned nsignals;
207unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200208int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000209
210int current_personality;
211
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000212#ifndef PERSONALITY0_WORDSIZE
213# define PERSONALITY0_WORDSIZE sizeof(long)
214#endif
215const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
216 PERSONALITY0_WORDSIZE,
217#if SUPPORTED_PERSONALITIES > 1
218 PERSONALITY1_WORDSIZE,
219#endif
220#if SUPPORTED_PERSONALITIES > 2
221 PERSONALITY2_WORDSIZE,
222#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200223};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000224
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200225void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000226set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227{
228 switch (personality) {
229 case 0:
230 errnoent = errnoent0;
231 nerrnos = nerrnos0;
232 sysent = sysent0;
233 nsyscalls = nsyscalls0;
234 ioctlent = ioctlent0;
235 nioctlents = nioctlents0;
236 signalent = signalent0;
237 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000238 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000239 break;
240
241#if SUPPORTED_PERSONALITIES >= 2
242 case 1:
243 errnoent = errnoent1;
244 nerrnos = nerrnos1;
245 sysent = sysent1;
246 nsyscalls = nsyscalls1;
247 ioctlent = ioctlent1;
248 nioctlents = nioctlents1;
249 signalent = signalent1;
250 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000251 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000252 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200253#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000254
255#if SUPPORTED_PERSONALITIES >= 3
256 case 2:
257 errnoent = errnoent2;
258 nerrnos = nerrnos2;
259 sysent = sysent2;
260 nsyscalls = nsyscalls2;
261 ioctlent = ioctlent2;
262 nioctlents = nioctlents2;
263 signalent = signalent2;
264 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000265 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000266 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200267#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000268 }
269
270 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271}
272
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000273#if SUPPORTED_PERSONALITIES > 1
274static void
275update_personality(struct tcb *tcp, int personality)
276{
277 if (personality == current_personality)
278 return;
279 set_personality(personality);
280
281 if (personality == tcp->currpers)
282 return;
283 tcp->currpers = personality;
284
285#if defined(POWERPC64) || defined(X86_64)
286 if (!qflag) {
287 static const char *const names[] = {"64 bit", "32 bit"};
288 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
289 tcp->pid, names[personality]);
290 }
291#endif
292}
293#endif
Roland McGrathe10e62a2004-09-04 04:20:43 +0000294
Roland McGrath9797ceb2002-12-30 10:23:00 +0000295static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000296
Roland McGrathe10e62a2004-09-04 04:20:43 +0000297static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000298 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000299 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000300 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000301 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000303 { QUAL_TRACE, "trace", qual_syscall, "system call" },
304 { QUAL_TRACE, "t", qual_syscall, "system call" },
305 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
306 { QUAL_ABBREV, "a", qual_syscall, "system call" },
307 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
308 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
309 { QUAL_RAW, "raw", qual_syscall, "system call" },
310 { QUAL_RAW, "x", qual_syscall, "system call" },
311 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
312 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
313 { QUAL_SIGNAL, "s", qual_signal, "signal" },
314 { QUAL_FAULT, "fault", qual_fault, "fault" },
315 { QUAL_FAULT, "faults", qual_fault, "fault" },
316 { QUAL_FAULT, "m", qual_fault, "fault" },
317 { QUAL_READ, "read", qual_desc, "descriptor" },
318 { QUAL_READ, "reads", qual_desc, "descriptor" },
319 { QUAL_READ, "r", qual_desc, "descriptor" },
320 { QUAL_WRITE, "write", qual_desc, "descriptor" },
321 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
322 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000323 { 0, NULL, NULL, NULL },
324};
325
Roland McGrath9797ceb2002-12-30 10:23:00 +0000326static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000327qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000328{
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 if (pers == 0 || pers < 0) {
330 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000331 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000332 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000333 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000334 }
335
336#if SUPPORTED_PERSONALITIES >= 2
337 if (pers == 1 || pers < 0) {
338 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000339 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000341 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000342 }
343#endif /* SUPPORTED_PERSONALITIES >= 2 */
344
345#if SUPPORTED_PERSONALITIES >= 3
346 if (pers == 2 || pers < 0) {
347 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000348 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000349 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000350 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000353}
354
355static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000356qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000357{
358 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000359 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000360
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000361 if (isdigit((unsigned char)*s)) {
362 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000363 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000364 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000365 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000366 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000367 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000368 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000369 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000370 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000373
374#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000375 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000376 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000377 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000378 rc = 0;
379 }
380#endif /* SUPPORTED_PERSONALITIES >= 2 */
381
382#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000383 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000384 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000385 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000386 rc = 0;
387 }
388#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000389
Roland McGrathfe6b3522005-02-02 04:40:11 +0000390 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000391}
392
393static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000394qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395{
396 int i;
397 char buf[32];
398
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000399 if (isdigit((unsigned char)*s)) {
400 int signo = atoi(s);
401 if (signo < 0 || signo >= MAX_QUALS)
402 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000403 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000404 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000405 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000406 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000407 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000408 strcpy(buf, s);
409 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000410 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000411 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000412 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000413 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000414 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000415 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 }
Roland McGrath76421df2005-02-02 03:51:18 +0000417 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000418}
419
420static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000421qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000422{
423 return -1;
424}
425
426static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000427qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000428{
Roland McGrath48a035f2006-01-12 09:45:56 +0000429 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000430 int desc = atoi(s);
431 if (desc < 0 || desc >= MAX_QUALS)
432 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000433 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000434 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000435 }
436 return -1;
437}
438
439static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000440lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
442 if (strcmp(s, "file") == 0)
443 return TRACE_FILE;
444 if (strcmp(s, "ipc") == 0)
445 return TRACE_IPC;
446 if (strcmp(s, "network") == 0)
447 return TRACE_NETWORK;
448 if (strcmp(s, "process") == 0)
449 return TRACE_PROCESS;
450 if (strcmp(s, "signal") == 0)
451 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000452 if (strcmp(s, "desc") == 0)
453 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000454 return -1;
455}
456
457void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000458qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000459{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000460 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000462 char *copy;
463 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 int i, n;
465
466 opt = &qual_options[0];
467 for (i = 0; (p = qual_options[i].option_name); i++) {
468 n = strlen(p);
469 if (strncmp(s, p, n) == 0 && s[n] == '=') {
470 opt = &qual_options[i];
471 s += n + 1;
472 break;
473 }
474 }
475 not = 0;
476 if (*s == '!') {
477 not = 1;
478 s++;
479 }
480 if (strcmp(s, "none") == 0) {
481 not = 1 - not;
482 s = "all";
483 }
484 if (strcmp(s, "all") == 0) {
485 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000486 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 }
488 return;
489 }
490 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000491 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200493 copy = strdup(s);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200494 if (!copy)
495 die_out_of_memory();
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000496 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000498 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000499 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000500 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000501
502#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000503 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000504 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000505 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000506#endif /* SUPPORTED_PERSONALITIES >= 2 */
507
508#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000509 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000510 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000511 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000512#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000513
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514 continue;
515 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000516 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000517 fprintf(stderr, "strace: invalid %s `%s'\n",
518 opt->argument_name, p);
519 exit(1);
520 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000521 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000522 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523 return;
524}
525
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000526#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000527enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000528#else /* FREEBSD */
529enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
530
531struct subcall {
532 int call;
533 int nsubcalls;
534 int subcalls[5];
535};
536
Roland McGratha4d48532005-06-08 20:45:28 +0000537static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000538 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000539#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000540 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000541#else
542 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
543#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000544 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
545};
546#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000547
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000548#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549
Roland McGratha4d48532005-06-08 20:45:28 +0000550static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200551decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000553 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200554 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000555 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000556
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557 switch (style) {
558 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000559 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
560 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200562 tcp->u_nargs = n = sysent[tcp->scno].nargs;
563 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564 tcp->u_arg[i] = tcp->u_arg[i + 1];
565 break;
566 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000567 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
568 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569 tcp->scno = subcall + tcp->u_arg[0];
570 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200571 tcp->u_nargs = n = sysent[tcp->scno].nargs;
572 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000573 if (size == sizeof(int)) {
574 unsigned int arg;
575 if (umove(tcp, addr, &arg) < 0)
576 arg = 0;
577 tcp->u_arg[i] = arg;
578 }
579 else if (size == sizeof(long)) {
580 unsigned long arg;
581 if (umove(tcp, addr, &arg) < 0)
582 arg = 0;
583 tcp->u_arg[i] = arg;
584 }
585 else
586 abort();
587 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 break;
590 case mask_style:
591 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592 for (i = 0; mask; i++)
593 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000594 if (i >= nsubcalls)
595 return;
596 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200598 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000599 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000600 case door_style:
601 /*
602 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000603 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000604 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000605 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
606 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000607 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200608 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000609 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000610#ifdef FREEBSD
611 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000612 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000613 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000614 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000615 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
616 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
617 for (i = 0; i < tcp->u_nargs; i++)
618 tcp->u_arg[i] = tcp->u_arg[i + 1];
619 }
620 break;
621#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622 }
623}
624#endif
625
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200626int
627printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200629 if (entering(tcp)) {
630 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200632 for (i = 0; i < tcp->u_nargs; i++)
633 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
634 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 return 0;
636}
637
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200638long
639getrval2(struct tcb *tcp)
640{
641 long val = -1;
642
643#ifdef LINUX
644#if defined (SPARC) || defined (SPARC64)
645 struct pt_regs regs;
646 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
647 return -1;
648 val = regs.u_regs[U_REG_O1];
649#elif defined(SH)
650 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
651 return -1;
652#elif defined(IA64)
653 if (upeek(tcp, PT_R9, &val) < 0)
654 return -1;
655#endif
656#endif /* LINUX */
657
658#ifdef SUNOS4
659 if (upeek(tcp, uoff(u_rval2), &val) < 0)
660 return -1;
661#endif /* SUNOS4 */
662
663#ifdef SVR4
664#ifdef SPARC
665 val = tcp->status.PR_REG[R_O1];
666#endif /* SPARC */
667#ifdef I386
668 val = tcp->status.PR_REG[EDX];
669#endif /* I386 */
670#ifdef X86_64
671 val = tcp->status.PR_REG[RDX];
672#endif /* X86_64 */
673#ifdef MIPS
674 val = tcp->status.PR_REG[CTX_V1];
675#endif /* MIPS */
676#endif /* SVR4 */
677
678#ifdef FREEBSD
679 struct reg regs;
680 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
681 val = regs.r_edx;
682#endif
683 return val;
684}
685
686#ifdef SUNOS4
687/*
688 * Apparently, indirect system calls have already be converted by ptrace(2),
689 * so if you see "indir" this program has gone astray.
690 */
691int
692sys_indir(struct tcb *tcp)
693{
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200694 int i, nargs;
695 long scno;
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200696
697 if (entering(tcp)) {
698 scno = tcp->u_arg[0];
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200699 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenkofabaa912011-08-25 01:23:10 +0200700 fprintf(stderr, "Bogus syscall: %ld\n", scno);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200701 return 0;
702 }
703 nargs = sysent[scno].nargs;
Denys Vlasenko5940e652011-09-01 09:55:05 +0200704 tprints(sysent[scno].sys_name);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200705 for (i = 0; i < nargs; i++)
706 tprintf(", %#lx", tcp->u_arg[i+1]);
707 }
708 return 0;
709}
710#endif /* SUNOS4 */
711
712int
713is_restart_error(struct tcb *tcp)
714{
715#ifdef LINUX
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200716 switch (tcp->u_error) {
717 case ERESTARTSYS:
718 case ERESTARTNOINTR:
719 case ERESTARTNOHAND:
720 case ERESTART_RESTARTBLOCK:
721 return 1;
722 default:
723 break;
724 }
725#endif /* LINUX */
726 return 0;
727}
728
Wichert Akkermanc7926982000-04-10 22:22:31 +0000729#ifdef LINUX
Denys Vlasenkob11322f2012-01-10 16:40:35 +0100730# if defined(I386)
731struct pt_regs i386_regs;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200732# elif defined(X86_64)
Denys Vlasenkoe73a89d2012-01-18 11:07:24 +0100733/*
734 * On 32 bits, pt_regs and user_regs_struct are the same,
735 * but on 64 bits, user_regs_struct has six more fields:
736 * fs_base, gs_base, ds, es, fs, gs.
737 * PTRACE_GETREGS fills them too, so struct pt_regs would overflow.
738 */
739static struct user_regs_struct x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200740# elif defined (IA64)
741long r8, r10, psr; /* TODO: make static? */
742long ia32 = 0; /* not static */
743# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200744static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200745# elif defined (M68K)
746static long d0;
747# elif defined(BFIN)
748static long r0;
749# elif defined (ARM)
750static struct pt_regs regs;
751# elif defined (ALPHA)
752static long r0;
753static long a3;
754# elif defined(AVR32)
755static struct pt_regs regs;
756# elif defined (SPARC) || defined (SPARC64)
757static struct pt_regs regs;
758static unsigned long trap;
759# elif defined(LINUX_MIPSN32)
760static long long a3;
761static long long r2;
762# elif defined(MIPS)
763static long a3;
764static long r2;
765# elif defined(S390) || defined(S390X)
766static long gpr2;
767static long pc;
768static long syscall_mode;
769# elif defined(HPPA)
770static long r28;
771# elif defined(SH)
772static long r0;
773# elif defined(SH64)
774static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200775# elif defined(CRISV10) || defined(CRISV32)
776static long r10;
777# elif defined(MICROBLAZE)
778static long r3;
779# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000780#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200782struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000783#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000784
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200785/* Returns:
786 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
787 * 1: ok, continue in trace_syscall().
788 * other: error, trace_syscall() should print error indicator
789 * ("????" etc) and bail out.
790 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200791#ifndef USE_PROCFS
792static
793#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200795get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000800# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000801 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200802 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000803
804 if (syscall_mode != -ENOSYS) {
805 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000806 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000807 */
808 scno = syscall_mode;
809 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000810 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000811 * Old style of "passing" the scno via the SVC instruction.
812 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000813 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200814 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200815 static const int gpr_offset[16] = {
816 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
817 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
818 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
819 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
820 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000821
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000822 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000823 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000824 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000825 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000826 if (errno) {
827 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000829 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000830
831 /*
832 * We have to check if the SVC got executed directly or via an
833 * EXECUTE instruction. In case of EXECUTE it is necessary to do
834 * instruction decoding to derive the system call number.
835 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
836 * so that this doesn't work if a SVC opcode is part of an EXECUTE
837 * opcode. Since there is no way to find out the opcode size this
838 * is the best we can do...
839 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 if ((opcode & 0xff00) == 0x0a00) {
841 /* SVC opcode */
842 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000843 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000844 else {
845 /* SVC got executed by EXECUTE instruction */
846
847 /*
848 * Do instruction decoding of EXECUTE. If you really want to
849 * understand this, read the Principles of Operations.
850 */
851 svc_addr = (void *) (opcode & 0xfff);
852
853 tmp = 0;
854 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000855 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 return -1;
857 svc_addr += tmp;
858
859 tmp = 0;
860 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000861 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000862 return -1;
863 svc_addr += tmp;
864
Denys Vlasenkofb036672009-01-23 16:30:26 +0000865 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000866 if (errno)
867 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000868# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000869 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000870# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000871 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000872# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000873 tmp = 0;
874 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000875 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000876 return -1;
877
878 scno = (scno | tmp) & 0xff;
879 }
880 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000881# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000882 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200884# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200885 /* TODO: speed up strace by not doing this at every syscall.
886 * We only need to do it after execve.
887 */
888 int currpers;
889 long val;
890 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200891
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200892 /* Check for 64/32 bit mode. */
893 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
894 return -1;
895 /* SF is bit 0 of MSR */
896 if (val < 0)
897 currpers = 0;
898 else
899 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000900 update_personality(tcp, currpers);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200901# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000902# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200903 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000904 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
905 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200906 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000907# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000908 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000909 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000910# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200911 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200913 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000914# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200915 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200916 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
917 return -1;
918 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000919
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200920 /* Check CS register value. On x86-64 linux it is:
921 * 0x33 for long mode (64 bit)
922 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200923 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200924 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200925 case 0x23: currpers = 1; break;
926 case 0x33: currpers = 0; break;
927 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200928 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200929 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200930 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200931 currpers = current_personality;
932 break;
933 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000934# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200935 /* This version analyzes the opcode of a syscall instruction.
936 * (int 0x80 on i386 vs. syscall on x86-64)
937 * It works, but is too complicated.
938 */
939 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000940
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200941 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000942
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200943 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
944 rip -= 2;
945 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000946
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200947 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200948 if (errno)
949 fprintf(stderr, "ptrace_peektext failed: %s\n",
950 strerror(errno));
951 switch (call & 0xffff) {
952 /* x86-64: syscall = 0x0f 0x05 */
953 case 0x050f: currpers = 0; break;
954 /* i386: int 0x80 = 0xcd 0x80 */
955 case 0x80cd: currpers = 1; break;
956 default:
957 currpers = current_personality;
958 fprintf(stderr,
959 "Unknown syscall opcode (0x%04X) while "
960 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200961 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200962 break;
963 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000964# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000965 update_personality(tcp, currpers);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000966# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000967# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200968 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000969 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200970 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200971 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200972 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000973 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200974 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200978 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000979 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000980 return -1;
981
982 /*
983 * We only need to grab the syscall number on syscall entry.
984 */
985 if (regs.ARM_ip == 0) {
986 /*
987 * Note: we only deal with only 32-bit CPUs here.
988 */
989 if (regs.ARM_cpsr & 0x20) {
990 /*
991 * Get the Thumb-mode system call number
992 */
993 scno = regs.ARM_r7;
994 } else {
995 /*
996 * Get the ARM-mode system call number
997 */
998 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000999 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001000 if (errno)
1001 return -1;
1002
Roland McGrathf691bd22006-04-25 07:34:41 +00001003 /* Handle the EABI syscall convention. We do not
1004 bother converting structures between the two
1005 ABIs, but basic functionality should work even
1006 if strace and the traced program have different
1007 ABIs. */
1008 if (scno == 0xef000000) {
1009 scno = regs.ARM_r7;
1010 } else {
1011 if ((scno & 0x0ff00000) != 0x0f900000) {
1012 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1013 scno);
1014 return -1;
1015 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001016
Roland McGrathf691bd22006-04-25 07:34:41 +00001017 /*
1018 * Fixup the syscall number
1019 */
1020 scno &= 0x000fffff;
1021 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001022 }
Roland McGrath56703312008-05-20 01:35:55 +00001023 if (scno & 0x0f0000) {
1024 /*
1025 * Handle ARM specific syscall
1026 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001027 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +00001028 scno &= 0x0000ffff;
1029 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001030 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001031
Roland McGrath0f87c492003-06-03 23:29:04 +00001032 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001033 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1034 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001036# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001037 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001039# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001040 unsigned long long regs[38];
1041
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001042 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001043 return -1;
1044 a3 = regs[REG_A3];
1045 r2 = regs[REG_V0];
1046
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001047 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001048 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001049 if (a3 == 0 || a3 == -1) {
1050 if (debug)
1051 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001052 return 0;
1053 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001054 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001055# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001056 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001057 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001058 if (upeek(tcp, REG_V0, &scno) < 0)
1059 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001060
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001061 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001062 if (a3 == 0 || a3 == -1) {
1063 if (debug)
1064 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001065 return 0;
1066 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001067 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001068# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001069 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001071 if (upeek(tcp, REG_R0, &scno) < 0)
1072 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001074 /*
1075 * Do some sanity checks to figure out if it's
1076 * really a syscall entry
1077 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001078 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001079 if (a3 == 0 || a3 == -1) {
1080 if (debug)
1081 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 return 0;
1083 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001085# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001087 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 return -1;
1089
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001090 /* Disassemble the syscall trap. */
1091 /* Retrieve the syscall trap instruction. */
1092 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001093# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001094 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1095 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001096# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001097 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001099 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001100 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001101
1102 /* Disassemble the trap to see what personality to use. */
1103 switch (trap) {
1104 case 0x91d02010:
1105 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001106 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001107 break;
1108 case 0x91d0206d:
1109 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001110 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001111 break;
1112 case 0x91d02000:
1113 /* SunOS syscall trap. (pers 1) */
1114 fprintf(stderr, "syscall: SunOS no support\n");
1115 return -1;
1116 case 0x91d02008:
1117 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001118 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001119 break;
1120 case 0x91d02009:
1121 /* NetBSD/FreeBSD syscall trap. */
1122 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1123 return -1;
1124 case 0x91d02027:
1125 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001126 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001127 break;
1128 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001129# if defined (SPARC64)
1130 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1131# else
1132 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1133# endif
1134 return -1;
1135 }
1136
1137 /* Extract the system call number from the registers. */
1138 if (trap == 0x91d02027)
1139 scno = 156;
1140 else
1141 scno = regs.u_regs[U_REG_G1];
1142 if (scno == 0) {
1143 scno = regs.u_regs[U_REG_O0];
1144 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1145 }
1146# elif defined(HPPA)
1147 if (upeek(tcp, PT_GR20, &scno) < 0)
1148 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001149# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001150 /*
1151 * In the new syscall ABI, the system call number is in R3.
1152 */
1153 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1154 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001155
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001156 if (scno < 0) {
1157 /* Odd as it may seem, a glibc bug has been known to cause
1158 glibc to issue bogus negative syscall numbers. So for
1159 our purposes, make strace print what it *should* have been */
1160 long correct_scno = (scno & 0xff);
1161 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001162 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001163 "Detected glibc bug: bogus system call"
1164 " number = %ld, correcting to %ld\n",
1165 scno,
1166 correct_scno);
1167 scno = correct_scno;
1168 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001169# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001170 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001171 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001172 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001173# elif defined(CRISV10) || defined(CRISV32)
1174 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1175 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001176# elif defined(TILE)
1177 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1178 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001179# elif defined(MICROBLAZE)
1180 if (upeek(tcp, 0, &scno) < 0)
1181 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001182# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001186 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001188#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001189 /* new syscall ABI returns result in R0 */
1190 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1191 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001192#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001193 /* ABI defines result returned in r9 */
1194 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1195 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001197
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001198#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001199# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001200 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001201# else
1202# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001203 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001205 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001206 perror("pread");
1207 return -1;
1208 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001209 switch (regs.r_eax) {
1210 case SYS_syscall:
1211 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001212 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1213 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 scno = regs.r_eax;
1216 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001217 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001218# endif /* FREEBSD */
1219# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001222 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001223 return 1;
1224}
1225
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001226/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001227 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001228 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001229 * 1: ok, continue in trace_syscall().
1230 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001231 * ("????" etc) and bail out.
1232 */
Roland McGratha4d48532005-06-08 20:45:28 +00001233static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001234syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001235{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001236#ifdef USE_PROCFS
Dmitry V. Levin44824b92012-02-20 21:44:53 +00001237 int scno = tcp->scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001238
Denys Vlasenkoece98792011-08-25 10:25:35 +02001239 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1240 if (
1241 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001243 || scno == SYS_vfork
1244#endif
John Hughes4e36a812001-04-18 15:11:51 +00001245#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001246 || scno == SYS_fork1
1247#endif
John Hughes4e36a812001-04-18 15:11:51 +00001248#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001249 || scno == SYS_forkall
1250#endif
John Hughes4e36a812001-04-18 15:11:51 +00001251#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001252 || scno == SYS_rfork1
1253#endif
John Hughes4e36a812001-04-18 15:11:51 +00001254#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001255 || scno == SYS_rforkall
1256#endif
1257 ) {
1258 /* We are returning in the child, fake it. */
1259 tcp->status.PR_WHY = PR_SYSENTRY;
1260 trace_syscall(tcp);
1261 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001263 else {
1264 fprintf(stderr, "syscall: missing entry\n");
1265 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 }
1267 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001268#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001269
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001271 if (scno == 0) {
1272 fprintf(stderr, "syscall: missing entry\n");
1273 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001275#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001276
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001278 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001280 if (i386_regs.eax != -ENOSYS) {
1281 if (debug)
1282 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1283 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001285#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001286 {
1287 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001288 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001289 rax = (int)rax; /* sign extend from 32 bits */
1290 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001291 if (debug)
1292 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1293 return 0;
1294 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001295 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001296#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001297 /* TODO: we already fetched PT_GPR2 in get_scno
1298 * and stored it in syscall_mode, reuse it here
1299 * instead of re-fetching?
1300 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001301 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001302 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001303 if (syscall_mode != -ENOSYS)
1304 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001305 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001306 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001307 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001308 return 0;
1309 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001311 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001312 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001314 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001316 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 return 0;
1318 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001319#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001320 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001321 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001322 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001323 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001324 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001325 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001326 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001327 return 0;
1328 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001329#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001330 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001331 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001332 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001333 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001334 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001335 return 0;
1336 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001337#elif defined(MICROBLAZE)
1338 if (upeek(tcp, 3 * 4, &r3) < 0)
1339 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001340 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001341 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001342 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001343 return 0;
1344 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001345#endif
1346#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001347 return 1;
1348}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001349
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001350static int
1351internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001352{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001353 /*
1354 * We must always trace a few critical system calls in order to
1355 * correctly support following forks in the presence of tracing
1356 * qualifiers.
1357 */
1358 int (*func)();
1359
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001360 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001361 return 0;
1362
1363 func = sysent[tcp->scno].sys_func;
1364
1365 if ( sys_fork == func
1366#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1367 || sys_vfork == func
1368#endif
1369#ifdef LINUX
1370 || sys_clone == func
1371#endif
1372#if UNIXWARE > 2
1373 || sys_rfork == func
1374#endif
1375 )
1376 return internal_fork(tcp);
1377
1378#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1379 if ( sys_execve == func
1380# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1381 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001382# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001383# if UNIXWARE > 2
1384 || sys_rexecve == func
1385# endif
1386 )
1387 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001388#endif
1389
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001390 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001391}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392
Roland McGratha4d48532005-06-08 20:45:28 +00001393static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001394syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001395{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001396#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001397 int i, nargs;
1398
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001399 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001400 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001401 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001402 nargs = tcp->u_nargs = MAX_ARGS;
1403
1404# if defined(S390) || defined(S390X)
1405 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001406 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1407 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001408# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001409 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001410 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1411 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001412# elif defined(IA64)
1413 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001414 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001415 long rbs_end;
1416 /* be backwards compatible with kernel < 2.4.4... */
1417# ifndef PT_RBS_END
1418# define PT_RBS_END PT_AR_BSP
1419# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001420
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001421 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1422 return -1;
1423 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001424 return -1;
1425
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426 sof = (cfm >> 0) & 0x7f;
1427 sol = (cfm >> 7) & 0x7f;
1428 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1429
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001430 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001431 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1432 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1433 return -1;
1434 }
1435 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001436 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1437 PT_R9 /* ECX = out1 */,
1438 PT_R10 /* EDX = out2 */,
1439 PT_R14 /* ESI = out3 */,
1440 PT_R15 /* EDI = out4 */,
1441 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001442
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001443 for (i = 0; i < nargs; ++i) {
1444 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1445 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001446 /* truncate away IVE sign-extension */
1447 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001448 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001449 }
1450# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1451 /* N32 and N64 both use up to six registers. */
1452 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001453
1454 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1455 return -1;
1456
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001457 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001458 tcp->u_arg[i] = regs[REG_A0 + i];
1459# if defined(LINUX_MIPSN32)
1460 tcp->ext_arg[i] = regs[REG_A0 + i];
1461# endif
1462 }
1463# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001464 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001465 long sp;
1466
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001467 if (upeek(tcp, REG_SP, &sp) < 0)
1468 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001469 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001470 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1471 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001472 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001473 (char *)(tcp->u_arg + 4));
1474 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001475 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001476 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001477 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001479# elif defined(POWERPC)
1480# ifndef PT_ORIG_R3
1481# define PT_ORIG_R3 34
1482# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001483 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001484 if (upeek(tcp, (i==0) ?
1485 (sizeof(unsigned long) * PT_ORIG_R3) :
1486 ((i+PT_R3) * sizeof(unsigned long)),
1487 &tcp->u_arg[i]) < 0)
1488 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001490# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001491 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001492 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1493# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001494 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001495 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1496 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001497# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001498 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001499 tcp->u_arg[i] = regs.uregs[i];
1500# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001501 (void)i;
1502 (void)nargs;
1503 tcp->u_arg[0] = regs.r12;
1504 tcp->u_arg[1] = regs.r11;
1505 tcp->u_arg[2] = regs.r10;
1506 tcp->u_arg[3] = regs.r9;
1507 tcp->u_arg[4] = regs.r5;
1508 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001509# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001510 static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001511
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001512 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001513 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1514 return -1;
1515# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001516 static const int syscall_regs[MAX_ARGS] = {
1517 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1518 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001519 };
1520
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001521 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001522 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001523 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001524# elif defined(SH64)
1525 int i;
1526 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001527 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001528
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001529 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001530 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1531 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001532# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001533 (void)i;
1534 (void)nargs;
1535 if (current_personality == 0) { /* x86-64 ABI */
1536 tcp->u_arg[0] = x86_64_regs.rdi;
1537 tcp->u_arg[1] = x86_64_regs.rsi;
1538 tcp->u_arg[2] = x86_64_regs.rdx;
1539 tcp->u_arg[3] = x86_64_regs.r10;
1540 tcp->u_arg[4] = x86_64_regs.r8;
1541 tcp->u_arg[5] = x86_64_regs.r9;
1542 } else { /* i386 ABI */
1543 /* Sign-extend lower 32 bits */
1544 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1545 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1546 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1547 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1548 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1549 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1550 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001551# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001552 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001553 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1554 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001555# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001556 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001557 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001558 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001559 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001560
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001561 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001562 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1563 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001564# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001565 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001566 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1567 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001568# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001569 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001570 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1571 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001572# elif defined(I386)
1573 (void)i;
1574 (void)nargs;
1575 tcp->u_arg[0] = i386_regs.ebx;
1576 tcp->u_arg[1] = i386_regs.ecx;
1577 tcp->u_arg[2] = i386_regs.edx;
1578 tcp->u_arg[3] = i386_regs.esi;
1579 tcp->u_arg[4] = i386_regs.edi;
1580 tcp->u_arg[5] = i386_regs.ebp;
1581# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001582 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001583 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1584 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001585# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001586#endif /* LINUX */
1587#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001588 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001589 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001590 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001591 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001592 nargs = tcp->u_nargs = MAX_ARGS;
1593 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001594 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001596 if (upeek(tcp, uoff(u_arg[0]) +
1597 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1598 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 }
1600#endif /* SUNOS4 */
1601#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001602# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 /*
1604 * SGI is broken: even though it has pr_sysarg, it doesn't
1605 * set them on system call entry. Get a clue.
1606 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001607 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608 tcp->u_nargs = sysent[tcp->scno].nargs;
1609 else
1610 tcp->u_nargs = tcp->status.pr_nsysarg;
1611 if (tcp->u_nargs > 4) {
1612 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001613 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001615 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 }
1617 else {
1618 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001619 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001621# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001622 /*
1623 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1624 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001625 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001626 tcp->u_nargs = sysent[tcp->scno].nargs;
1627 else
1628 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1629 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001630 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1631# elif defined(HAVE_PR_SYSCALL)
1632 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001633 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634 tcp->u_nargs = sysent[tcp->scno].nargs;
1635 else
1636 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001637 for (i = 0; i < tcp->u_nargs; i++)
1638 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1639# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001640 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 tcp->u_nargs = sysent[tcp->scno].nargs;
1642 else
1643 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001644 if (tcp->u_nargs > 0)
1645 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001646 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1647# else
John Hughes25299712001-03-06 10:10:06 +00001648 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001649# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001651#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001652 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001653 sysent[tcp->scno].nargs > tcp->status.val)
1654 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001655 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001656 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001657 if (tcp->u_nargs < 0)
1658 tcp->u_nargs = 0;
1659 if (tcp->u_nargs > MAX_ARGS)
1660 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001661 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001662 case SYS___syscall:
1663 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1664 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001665 break;
1666 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001667 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1668 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001669 break;
1670 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001671 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1672 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001673 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001674 }
1675#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001676 return 1;
1677}
1678
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001679static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001680trace_syscall_entering(struct tcb *tcp)
1681{
1682 int res, scno_good;
1683
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001684#if defined TCB_WAITEXECVE
1685 if (tcp->flags & TCB_WAITEXECVE) {
1686 /* This is the post-execve SIGTRAP. */
1687 tcp->flags &= ~TCB_WAITEXECVE;
1688 return 0;
1689 }
1690#endif
1691
Denys Vlasenko06602d92011-08-24 17:53:52 +02001692 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001693 if (res == 0)
1694 return res;
1695 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001696 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001697 if (res == 0)
1698 return res;
1699 if (res == 1)
1700 res = syscall_enter(tcp);
1701 if (res == 0)
1702 return res;
1703
1704 if (res != 1) {
1705 printleader(tcp);
1706 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001707 if (scno_good != 1)
1708 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001709 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001710 tprintf("syscall_%lu(", tcp->scno);
1711 else
1712 tprintf("%s(", sysent[tcp->scno].sys_name);
1713 /*
1714 * " <unavailable>" will be added later by the code which
1715 * detects ptrace errors.
1716 */
1717 goto ret;
1718 }
1719
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001720#if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall)
1721 while (SCNO_IN_RANGE(tcp->scno)) {
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001722#ifdef SYS_socket_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001723 if (sysent[tcp->scno].sys_func == sys_socketcall) {
1724 decode_subcall(tcp, SYS_socket_subcall,
1725 SYS_socket_nsubcalls, deref_style);
1726 break;
1727 }
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001728#endif
1729#ifdef SYS_ipc_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001730 if (sysent[tcp->scno].sys_func == sys_ipc) {
1731 decode_subcall(tcp, SYS_ipc_subcall,
1732 SYS_ipc_nsubcalls, shift_style);
1733 break;
1734 }
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001735#endif
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001736 break;
1737 }
1738#endif /* SYS_socket_subcall || SYS_ipc_subcall */
1739
1740#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
Dmitry V. Levin44824b92012-02-20 21:44:53 +00001741 switch (tcp->scno) {
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001742#ifdef SVR4
1743#ifdef SYS_pgrpsys_subcall
1744 case SYS_pgrpsys:
1745 decode_subcall(tcp, SYS_pgrpsys_subcall,
1746 SYS_pgrpsys_nsubcalls, shift_style);
1747 break;
1748#endif /* SYS_pgrpsys_subcall */
1749#ifdef SYS_sigcall_subcall
1750 case SYS_sigcall:
1751 decode_subcall(tcp, SYS_sigcall_subcall,
1752 SYS_sigcall_nsubcalls, mask_style);
1753 break;
1754#endif /* SYS_sigcall_subcall */
1755 case SYS_msgsys:
1756 decode_subcall(tcp, SYS_msgsys_subcall,
1757 SYS_msgsys_nsubcalls, shift_style);
1758 break;
1759 case SYS_shmsys:
1760 decode_subcall(tcp, SYS_shmsys_subcall,
1761 SYS_shmsys_nsubcalls, shift_style);
1762 break;
1763 case SYS_semsys:
1764 decode_subcall(tcp, SYS_semsys_subcall,
1765 SYS_semsys_nsubcalls, shift_style);
1766 break;
1767 case SYS_sysfs:
1768 decode_subcall(tcp, SYS_sysfs_subcall,
1769 SYS_sysfs_nsubcalls, shift_style);
1770 break;
1771 case SYS_spcall:
1772 decode_subcall(tcp, SYS_spcall_subcall,
1773 SYS_spcall_nsubcalls, shift_style);
1774 break;
1775#ifdef SYS_context_subcall
1776 case SYS_context:
1777 decode_subcall(tcp, SYS_context_subcall,
1778 SYS_context_nsubcalls, shift_style);
1779 break;
1780#endif /* SYS_context_subcall */
1781#ifdef SYS_door_subcall
1782 case SYS_door:
1783 decode_subcall(tcp, SYS_door_subcall,
1784 SYS_door_nsubcalls, door_style);
1785 break;
1786#endif /* SYS_door_subcall */
1787#ifdef SYS_kaio_subcall
1788 case SYS_kaio:
1789 decode_subcall(tcp, SYS_kaio_subcall,
1790 SYS_kaio_nsubcalls, shift_style);
1791 break;
1792#endif
1793#endif /* SVR4 */
1794#ifdef FREEBSD
1795 case SYS_msgsys:
1796 case SYS_shmsys:
1797 case SYS_semsys:
1798 decode_subcall(tcp, 0, 0, table_style);
1799 break;
1800#endif
1801#ifdef SUNOS4
1802 case SYS_semsys:
1803 decode_subcall(tcp, SYS_semsys_subcall,
1804 SYS_semsys_nsubcalls, shift_style);
1805 break;
1806 case SYS_msgsys:
1807 decode_subcall(tcp, SYS_msgsys_subcall,
1808 SYS_msgsys_nsubcalls, shift_style);
1809 break;
1810 case SYS_shmsys:
1811 decode_subcall(tcp, SYS_shmsys_subcall,
1812 SYS_shmsys_nsubcalls, shift_style);
1813 break;
1814#endif
1815 }
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001816#endif /* SVR4 || FREEBSD || SUNOS4 */
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001817
1818 internal_syscall(tcp);
1819
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001820 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001821 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1822 (tracing_paths && !pathtrace_match(tcp))) {
1823 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1824 return 0;
1825 }
1826
1827 tcp->flags &= ~TCB_FILTERED;
1828
1829 if (cflag == CFLAG_ONLY_STATS) {
1830 res = 0;
1831 goto ret;
1832 }
1833
1834 printleader(tcp);
1835 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001836 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001837 tprintf("syscall_%lu(", tcp->scno);
1838 else
1839 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001840 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001841 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1842 sysent[tcp->scno].sys_func != sys_exit))
1843 res = printargs(tcp);
1844 else
1845 res = (*sysent[tcp->scno].sys_func)(tcp);
1846
1847 if (fflush(tcp->outf) == EOF)
1848 return -1;
1849 ret:
1850 tcp->flags |= TCB_INSYSCALL;
1851 /* Measure the entrance time as late as possible to avoid errors. */
1852 if (dtime || cflag)
1853 gettimeofday(&tcp->etime, NULL);
1854 return res;
1855}
1856
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001857/* Returns:
1858 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1859 * 1: ok, continue in trace_syscall().
1860 * other: error, trace_syscall() should print error indicator
1861 * ("????" etc) and bail out.
1862 */
1863static int
1864get_syscall_result(struct tcb *tcp)
1865{
1866#ifdef LINUX
1867# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001868 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1869 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001870# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001871# define SO_MASK 0x10000000
1872 {
1873 long flags;
1874 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1875 return -1;
1876 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1877 return -1;
1878 if (flags & SO_MASK)
1879 result = -result;
1880 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001881# elif defined(AVR32)
1882 /* Read complete register set in one go. */
1883 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1884 return -1;
1885# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001886 if (upeek(tcp, PT_R0, &r0) < 0)
1887 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001888# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001889 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001890 return -1;
1891# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001892 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001893 return -1;
1894# elif defined(IA64)
1895# define IA64_PSR_IS ((long)1 << 34)
1896 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1897 ia32 = (psr & IA64_PSR_IS) != 0;
1898 if (upeek(tcp, PT_R8, &r8) < 0)
1899 return -1;
1900 if (upeek(tcp, PT_R10, &r10) < 0)
1901 return -1;
1902# elif defined (ARM)
1903 /* Read complete register set in one go. */
1904 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1905 return -1;
1906# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001907 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1908 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001909# elif defined (LINUX_MIPSN32)
1910 unsigned long long regs[38];
1911
1912 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1913 return -1;
1914 a3 = regs[REG_A3];
1915 r2 = regs[REG_V0];
1916# elif defined (MIPS)
1917 if (upeek(tcp, REG_A3, &a3) < 0)
1918 return -1;
1919 if (upeek(tcp, REG_V0, &r2) < 0)
1920 return -1;
1921# elif defined (ALPHA)
1922 if (upeek(tcp, REG_A3, &a3) < 0)
1923 return -1;
1924 if (upeek(tcp, REG_R0, &r0) < 0)
1925 return -1;
1926# elif defined (SPARC) || defined (SPARC64)
1927 /* Everything we need is in the current register set. */
1928 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1929 return -1;
1930# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001931 if (upeek(tcp, PT_GR28, &r28) < 0)
1932 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001933# elif defined(SH)
1934# elif defined(SH64)
1935# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001936 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1937 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001938# elif defined(TILE)
1939# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001940 if (upeek(tcp, 3 * 4, &r3) < 0)
1941 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001942# endif
1943#endif /* LINUX */
1944
1945#ifdef SUNOS4
1946#elif defined(SH)
1947 /* new syscall ABI returns result in R0 */
1948 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1949 return -1;
1950#elif defined(SH64)
1951 /* ABI defines result returned in r9 */
1952 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1953 return -1;
1954#endif
1955
1956#ifdef USE_PROCFS
1957# ifndef HAVE_PR_SYSCALL
1958# ifdef FREEBSD
1959 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1960 perror("pread");
1961 return -1;
1962 }
1963# endif /* FREEBSD */
1964# endif /* !HAVE_PR_SYSCALL */
1965#endif /* USE_PROCFS */
1966
1967 return 1;
1968}
1969
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001970/* Called at each syscall exit.
1971 * Returns:
1972 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1973 * 1: ok, continue in trace_syscall().
1974 * other: error, trace_syscall() should print error indicator
1975 * ("????" etc) and bail out.
1976 */
1977static int
1978syscall_fixup_on_sysexit(struct tcb *tcp)
1979{
1980#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001981 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1982 fprintf(stderr, "syscall: missing exit\n");
1983 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001984 }
1985#endif /* USE_PROCFS */
1986
1987#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001988 {
Dmitry V. Levin44824b92012-02-20 21:44:53 +00001989 int scno = tcp->scno;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001990 if (scno != 0) {
1991 if (debug) {
1992 /*
1993 * This happens when a signal handler
1994 * for a signal which interrupted a
1995 * a system call makes another system call.
1996 */
1997 fprintf(stderr, "syscall: missing exit\n");
1998 }
1999 tcp->flags &= ~TCB_INSYSCALL;
2000 }
2001 }
2002#endif /* SUNOS4 */
2003
2004#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002005# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002006 if (syscall_mode != -ENOSYS)
2007 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002008 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002009 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2010 /*
2011 * Return from execve.
2012 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2013 * flag set for the post-execve SIGTRAP to see and reset.
2014 */
2015 gpr2 = 0;
2016 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002017# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002018#endif /* LINUX */
2019 return 1;
2020}
2021
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002022#ifdef LINUX
2023/*
2024 * Check the syscall return value register value for whether it is
2025 * a negated errno code indicating an error, or a success return value.
2026 */
2027static inline int
2028is_negated_errno(unsigned long int val)
2029{
2030 unsigned long int max = -(long int) nerrnos;
2031# if SUPPORTED_PERSONALITIES > 1
2032 if (personality_wordsize[current_personality] < sizeof(val)) {
2033 val = (unsigned int) val;
2034 max = (unsigned int) max;
2035 }
2036# endif
2037 return val > max;
2038}
2039#endif
2040
2041static int
2042get_error(struct tcb *tcp)
2043{
2044 int u_error = 0;
2045#ifdef LINUX
2046 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002047 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002048 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2049 check_errno = 0;
2050 }
2051# if defined(S390) || defined(S390X)
2052 if (check_errno && is_negated_errno(gpr2)) {
2053 tcp->u_rval = -1;
2054 u_error = -gpr2;
2055 }
2056 else {
2057 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002058 }
2059# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002060 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002061 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002062 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002063 }
2064 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002065 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002066 }
2067# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002068 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002069 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002070 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002071 }
2072 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002073 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002074 }
2075# elif defined(IA64)
2076 if (ia32) {
2077 int err;
2078
2079 err = (int)r8;
2080 if (check_errno && is_negated_errno(err)) {
2081 tcp->u_rval = -1;
2082 u_error = -err;
2083 }
2084 else {
2085 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002086 }
2087 } else {
2088 if (check_errno && r10) {
2089 tcp->u_rval = -1;
2090 u_error = r8;
2091 } else {
2092 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002093 }
2094 }
2095# elif defined(MIPS)
2096 if (check_errno && a3) {
2097 tcp->u_rval = -1;
2098 u_error = r2;
2099 } else {
2100 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002101 }
2102# elif defined(POWERPC)
2103 if (check_errno && is_negated_errno(result)) {
2104 tcp->u_rval = -1;
2105 u_error = -result;
2106 }
2107 else {
2108 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002109 }
2110# elif defined(M68K)
2111 if (check_errno && is_negated_errno(d0)) {
2112 tcp->u_rval = -1;
2113 u_error = -d0;
2114 }
2115 else {
2116 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002117 }
2118# elif defined(ARM)
2119 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2120 tcp->u_rval = -1;
2121 u_error = -regs.ARM_r0;
2122 }
2123 else {
2124 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002125 }
2126# elif defined(AVR32)
2127 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2128 tcp->u_rval = -1;
2129 u_error = -regs.r12;
2130 }
2131 else {
2132 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002133 }
2134# elif defined(BFIN)
2135 if (check_errno && is_negated_errno(r0)) {
2136 tcp->u_rval = -1;
2137 u_error = -r0;
2138 } else {
2139 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002140 }
2141# elif defined(ALPHA)
2142 if (check_errno && a3) {
2143 tcp->u_rval = -1;
2144 u_error = r0;
2145 }
2146 else {
2147 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002148 }
2149# elif defined(SPARC)
2150 if (check_errno && regs.psr & PSR_C) {
2151 tcp->u_rval = -1;
2152 u_error = regs.u_regs[U_REG_O0];
2153 }
2154 else {
2155 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002156 }
2157# elif defined(SPARC64)
2158 if (check_errno && regs.tstate & 0x1100000000UL) {
2159 tcp->u_rval = -1;
2160 u_error = regs.u_regs[U_REG_O0];
2161 }
2162 else {
2163 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002164 }
2165# elif defined(HPPA)
2166 if (check_errno && is_negated_errno(r28)) {
2167 tcp->u_rval = -1;
2168 u_error = -r28;
2169 }
2170 else {
2171 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002172 }
2173# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002174 if (check_errno && is_negated_errno(r0)) {
2175 tcp->u_rval = -1;
2176 u_error = -r0;
2177 }
2178 else {
2179 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002180 }
2181# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002182 if (check_errno && is_negated_errno(r9)) {
2183 tcp->u_rval = -1;
2184 u_error = -r9;
2185 }
2186 else {
2187 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002188 }
2189# elif defined(CRISV10) || defined(CRISV32)
2190 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2191 tcp->u_rval = -1;
2192 u_error = -r10;
2193 }
2194 else {
2195 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002196 }
2197# elif defined(TILE)
2198 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002199 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2200 return -1;
2201 if (check_errno && rval < 0 && rval > -nerrnos) {
2202 tcp->u_rval = -1;
2203 u_error = -rval;
2204 }
2205 else {
2206 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002207 }
2208# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002209 if (check_errno && is_negated_errno(r3)) {
2210 tcp->u_rval = -1;
2211 u_error = -r3;
2212 }
2213 else {
2214 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002215 }
2216# endif
2217#endif /* LINUX */
2218#ifdef SUNOS4
2219 /* get error code from user struct */
2220 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2221 return -1;
2222 u_error >>= 24; /* u_error is a char */
2223
2224 /* get system call return value */
2225 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2226 return -1;
2227#endif /* SUNOS4 */
2228#ifdef SVR4
2229# ifdef SPARC
2230 /* Judicious guessing goes a long way. */
2231 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2232 tcp->u_rval = -1;
2233 u_error = tcp->status.pr_reg[R_O0];
2234 }
2235 else {
2236 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002237 }
2238# endif /* SPARC */
2239# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002240 if (tcp->status.PR_REG[EFL] & 0x1) {
2241 tcp->u_rval = -1;
2242 u_error = tcp->status.PR_REG[EAX];
2243 }
2244 else {
2245 tcp->u_rval = tcp->status.PR_REG[EAX];
2246# ifdef HAVE_LONG_LONG
2247 tcp->u_lrval =
2248 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2249 tcp->status.PR_REG[EAX];
2250# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002251 }
2252# endif /* I386 */
2253# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002254 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2255 tcp->u_rval = -1;
2256 u_error = tcp->status.PR_REG[RAX];
2257 }
2258 else {
2259 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002260 }
2261# endif /* X86_64 */
2262# ifdef MIPS
2263 if (tcp->status.pr_reg[CTX_A3]) {
2264 tcp->u_rval = -1;
2265 u_error = tcp->status.pr_reg[CTX_V0];
2266 }
2267 else {
2268 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002269 }
2270# endif /* MIPS */
2271#endif /* SVR4 */
2272#ifdef FREEBSD
2273 if (regs.r_eflags & PSL_C) {
2274 tcp->u_rval = -1;
2275 u_error = regs.r_eax;
2276 } else {
2277 tcp->u_rval = regs.r_eax;
2278 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002279 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002280 }
2281#endif /* FREEBSD */
2282 tcp->u_error = u_error;
2283 return 1;
2284}
2285
2286static void
2287dumpio(struct tcb *tcp)
2288{
2289 if (syserror(tcp))
2290 return;
2291 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2292 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002293 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002294 return;
2295 if (sysent[tcp->scno].sys_func == printargs)
2296 return;
2297 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2298 if (sysent[tcp->scno].sys_func == sys_read ||
2299 sysent[tcp->scno].sys_func == sys_pread ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002300#ifdef SVR4
2301#if _LFS64_LARGEFILE
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002302 sysent[tcp->scno].sys_func == sys_pread64 ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002303#endif
2304#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002305 sysent[tcp->scno].sys_func == sys_recv ||
2306 sysent[tcp->scno].sys_func == sys_recvfrom)
2307 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2308 else if (sysent[tcp->scno].sys_func == sys_readv)
2309 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2310 return;
2311 }
2312 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2313 if (sysent[tcp->scno].sys_func == sys_write ||
2314 sysent[tcp->scno].sys_func == sys_pwrite ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002315#ifdef SVR4
2316#if _LFS64_LARGEFILE
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002317 sysent[tcp->scno].sys_func == sys_pwrite64 ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002318#endif
2319#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002320 sysent[tcp->scno].sys_func == sys_send ||
2321 sysent[tcp->scno].sys_func == sys_sendto)
2322 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2323 else if (sysent[tcp->scno].sys_func == sys_writev)
2324 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2325 return;
2326 }
2327}
2328
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002329static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002330trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331{
2332 int sys_res;
2333 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002334 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002337 /* Measure the exit time as early as possible to avoid errors. */
2338 if (dtime || cflag)
2339 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002340
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00002341#if SUPPORTED_PERSONALITIES > 1
2342 update_personality(tcp, tcp->currpers);
2343#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002344 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002345 if (res == 0)
2346 return res;
2347 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002348 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002349 if (res == 0)
2350 return res;
2351 if (res == 1)
2352 res = get_error(tcp);
2353 if (res == 0)
2354 return res;
2355 if (res == 1)
2356 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002357
Grant Edwards8a082772011-04-07 20:25:40 +00002358 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002359 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002360 }
2361
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002362 if (tcp->flags & TCB_REPRINT) {
2363 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002364 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002365 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002366 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002367 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002368 }
2369
2370 if (cflag) {
2371 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002372 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002373 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002374 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002375 }
2376 }
2377
2378 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002379 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002380 tabto();
Denys Vlasenko000b6012012-01-28 01:25:03 +01002381 tprints("= ? <unavailable>\n");
2382 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002383 tcp->flags &= ~TCB_INSYSCALL;
2384 return res;
2385 }
2386
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002387 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002388 || (qual_flags[tcp->scno] & QUAL_RAW))
2389 sys_res = printargs(tcp);
2390 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002391 /* FIXME: not_failing_only (IOW, option -z) is broken:
2392 * failure of syscall is known only after syscall return.
2393 * Thus we end up with something like this on, say, ENOENT:
2394 * open("doesnt_exist", O_RDONLY <unfinished ...>
2395 * {next syscall decode}
2396 * whereas the intended result is that open(...) line
2397 * is not shown at all.
2398 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002399 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002400 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002401 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2402 }
2403
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002404 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002405 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002406 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002407 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002408 qual_flags[tcp->scno] & QUAL_RAW) {
2409 if (u_error)
2410 tprintf("= -1 (errno %ld)", u_error);
2411 else
2412 tprintf("= %#lx", tcp->u_rval);
2413 }
2414 else if (!(sys_res & RVAL_NONE) && u_error) {
2415 switch (u_error) {
2416#ifdef LINUX
Denys Vlasenkofe585652012-01-12 11:26:34 +01002417 /* Blocked signals do not interrupt any syscalls.
2418 * In this case syscalls don't return ERESTARTfoo codes.
2419 *
2420 * Deadly signals set to SIG_DFL interrupt syscalls
2421 * and kill the process regardless of which of the codes below
2422 * is returned by the interrupted syscall.
2423 * In some cases, kernel forces a kernel-generated deadly
2424 * signal to be unblocked and set to SIG_DFL (and thus cause
2425 * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
2426 * or SIGILL. (The alternative is to leave process spinning
2427 * forever on the faulty instruction - not useful).
2428 *
2429 * SIG_IGNed signals and non-deadly signals set to SIG_DFL
2430 * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
2431 * but kernel will always restart them.
2432 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002433 case ERESTARTSYS:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002434 /* Most common type of signal-interrupted syscall exit code.
2435 * The system call will be restarted with the same arguments
2436 * if SA_RESTART is set; otherwise, it will fail with EINTR.
2437 */
2438 tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002439 break;
2440 case ERESTARTNOINTR:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002441 /* Rare. For example, fork() returns this if interrupted.
2442 * SA_RESTART is ignored (assumed set): the restart is unconditional.
2443 */
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002444 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002445 break;
2446 case ERESTARTNOHAND:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002447 /* pause(), rt_sigsuspend() etc use this code.
2448 * SA_RESTART is ignored (assumed not set):
2449 * syscall won't restart (will return EINTR instead)
2450 * even after signal with SA_RESTART set.
2451 * However, after SIG_IGN or SIG_DFL signal it will.
2452 */
2453 tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002454 break;
2455 case ERESTART_RESTARTBLOCK:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002456 /* Syscalls like nanosleep(), poll() which can't be
2457 * restarted with their original arguments use this
2458 * code. Kernel will execute restart_syscall() instead,
2459 * which changes arguments before restarting syscall.
2460 * SA_RESTART is ignored (assumed not set) similarly
2461 * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
2462 * since restart data is saved in "restart block"
2463 * in task struct, and if signal handler uses a syscall
2464 * which in turn saves another such restart block,
2465 * old data is lost and restart becomes impossible)
2466 */
2467 tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002468 break;
2469#endif /* LINUX */
2470 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002471 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002472 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002473 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002474 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002475 strerror(u_error));
2476 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002477 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002478 strerror(u_error));
2479 break;
2480 }
2481 if ((sys_res & RVAL_STR) && tcp->auxstr)
2482 tprintf(" (%s)", tcp->auxstr);
2483 }
2484 else {
2485 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002486 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002487 else {
2488 switch (sys_res & RVAL_MASK) {
2489 case RVAL_HEX:
2490 tprintf("= %#lx", tcp->u_rval);
2491 break;
2492 case RVAL_OCTAL:
2493 tprintf("= %#lo", tcp->u_rval);
2494 break;
2495 case RVAL_UDECIMAL:
2496 tprintf("= %lu", tcp->u_rval);
2497 break;
2498 case RVAL_DECIMAL:
2499 tprintf("= %ld", tcp->u_rval);
2500 break;
2501#ifdef HAVE_LONG_LONG
2502 case RVAL_LHEX:
2503 tprintf("= %#llx", tcp->u_lrval);
2504 break;
2505 case RVAL_LOCTAL:
2506 tprintf("= %#llo", tcp->u_lrval);
2507 break;
2508 case RVAL_LUDECIMAL:
2509 tprintf("= %llu", tcp->u_lrval);
2510 break;
2511 case RVAL_LDECIMAL:
2512 tprintf("= %lld", tcp->u_lrval);
2513 break;
2514#endif
2515 default:
2516 fprintf(stderr,
2517 "invalid rval format\n");
2518 break;
2519 }
2520 }
2521 if ((sys_res & RVAL_STR) && tcp->auxstr)
2522 tprintf(" (%s)", tcp->auxstr);
2523 }
2524 if (dtime) {
2525 tv_sub(&tv, &tv, &tcp->etime);
2526 tprintf(" <%ld.%06ld>",
2527 (long) tv.tv_sec, (long) tv.tv_usec);
2528 }
Denys Vlasenko000b6012012-01-28 01:25:03 +01002529 tprints("\n");
2530 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002531
2532 dumpio(tcp);
2533 if (fflush(tcp->outf) == EOF)
2534 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002535 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002536 tcp->flags &= ~TCB_INSYSCALL;
2537 return 0;
2538}
2539
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002540int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002541trace_syscall(struct tcb *tcp)
2542{
2543 return exiting(tcp) ?
2544 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2545}