blob: ec3eaab77103a53bd9bc2687d9de81b04e461cb2 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#include <sys/reg.h>
47#ifndef PTRACE_PEEKUSR
48# define PTRACE_PEEKUSR PTRACE_PEEKUSER
49#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000050#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070051#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000052# ifdef HAVE_STRUCT_IA64_FPREG
53# define ia64_fpreg XXX_ia64_fpreg
54# endif
55# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
56# define pt_all_user_regs XXX_pt_all_user_regs
57# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070058#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000059# undef ia64_fpreg
60# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000061#endif
62
Roland McGrath6d1a65c2004-07-12 07:44:08 +000063#if defined (LINUX) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000064# undef PTRACE_GETREGS
65# define PTRACE_GETREGS PTRACE_GETREGS64
66# undef PTRACE_SETREGS
67# define PTRACE_SETREGS PTRACE_SETREGS64
68#endif /* LINUX && SPARC64 */
69
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000070#if defined(LINUX) && defined(IA64)
71# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Pavel Machekd8ae7e32000-02-01 17:17:25 +000075#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#ifdef LINUX
77#ifndef ERESTARTSYS
78#define ERESTARTSYS 512
79#endif
80#ifndef ERESTARTNOINTR
81#define ERESTARTNOINTR 513
82#endif
83#ifndef ERESTARTNOHAND
84#define ERESTARTNOHAND 514 /* restart if no handler.. */
85#endif
86#ifndef ENOIOCTLCMD
87#define ENOIOCTLCMD 515 /* No ioctl command */
88#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000089#ifndef ERESTART_RESTARTBLOCK
90#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
91#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifndef NSIG
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020093#warning: NSIG is not defined, using 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000094#define NSIG 32
95#endif
96#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020097/* Ugh. Is this really correct? ARM has no RT signals?! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098#undef NSIG
99#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000100#undef NR_SYSCALL_BASE
101#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102#endif
103#endif /* LINUX */
104
105#include "syscall.h"
106
107/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000108#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000109#define TF TRACE_FILE
110#define TI TRACE_IPC
111#define TN TRACE_NETWORK
112#define TP TRACE_PROCESS
113#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000114#define NF SYSCALL_NEVER_FAILS
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200115#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116
Roland McGrathee36ce12004-09-04 03:53:10 +0000117static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118#include "syscallent.h"
119};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120
121#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000122static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#include "syscallent1.h"
124};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
133/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000134#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135#undef TF
136#undef TI
137#undef TN
138#undef TP
139#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000140#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200141#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
Denys Vlasenko39fca622011-08-20 02:12:33 +0200143
144/*
145 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
146 * program `ioctlsort', such that the list is sorted by the `code' field.
147 * This has the side-effect of resolving the _IO.. macros into
148 * plain integers, eliminating the need to include here everything
149 * in "/usr/include".
150 */
151
152
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent.h"
155};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200156static const char *const signalent0[] = {
157#include "signalent.h"
158};
159static const struct ioctlent ioctlent0[] = {
160#include "ioctlent.h"
161};
162enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
163enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
164enum { nsignals0 = ARRAY_SIZE(signalent0) };
165enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
166int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200172static const char *const signalent1[] = {
173#include "signalent1.h"
174};
175static const struct ioctlent ioctlent1[] = {
176#include "ioctlent1.h"
177};
178enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
179enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
180enum { nsignals1 = ARRAY_SIZE(signalent1) };
181enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
182int qual_flags1[MAX_QUALS];
183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184
185#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000186static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000187#include "errnoent2.h"
188};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200189static const char *const signalent2[] = {
190#include "signalent2.h"
191};
192static const struct ioctlent ioctlent2[] = {
193#include "ioctlent2.h"
194};
195enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
196enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
197enum { nsignals2 = ARRAY_SIZE(signalent2) };
198enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
199int qual_flags2[MAX_QUALS];
200#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201
Denys Vlasenko39fca622011-08-20 02:12:33 +0200202
203const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000204const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200205const char *const *signalent;
206const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200207unsigned nsyscalls;
208unsigned nerrnos;
209unsigned nsignals;
210unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200211int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212
213int current_personality;
214
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000215#ifndef PERSONALITY0_WORDSIZE
216# define PERSONALITY0_WORDSIZE sizeof(long)
217#endif
218const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
219 PERSONALITY0_WORDSIZE,
220#if SUPPORTED_PERSONALITIES > 1
221 PERSONALITY1_WORDSIZE,
222#endif
223#if SUPPORTED_PERSONALITIES > 2
224 PERSONALITY2_WORDSIZE,
225#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000227
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200228void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000229set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000230{
231 switch (personality) {
232 case 0:
233 errnoent = errnoent0;
234 nerrnos = nerrnos0;
235 sysent = sysent0;
236 nsyscalls = nsyscalls0;
237 ioctlent = ioctlent0;
238 nioctlents = nioctlents0;
239 signalent = signalent0;
240 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000241 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 break;
243
244#if SUPPORTED_PERSONALITIES >= 2
245 case 1:
246 errnoent = errnoent1;
247 nerrnos = nerrnos1;
248 sysent = sysent1;
249 nsyscalls = nsyscalls1;
250 ioctlent = ioctlent1;
251 nioctlents = nioctlents1;
252 signalent = signalent1;
253 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000254 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200256#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000257
258#if SUPPORTED_PERSONALITIES >= 3
259 case 2:
260 errnoent = errnoent2;
261 nerrnos = nerrnos2;
262 sysent = sysent2;
263 nsyscalls = nsyscalls2;
264 ioctlent = ioctlent2;
265 nioctlents = nioctlents2;
266 signalent = signalent2;
267 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000268 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200270#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271 }
272
273 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274}
275
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000276#if SUPPORTED_PERSONALITIES > 1
277static void
278update_personality(struct tcb *tcp, int personality)
279{
280 if (personality == current_personality)
281 return;
282 set_personality(personality);
283
284 if (personality == tcp->currpers)
285 return;
286 tcp->currpers = personality;
287
288#if defined(POWERPC64) || defined(X86_64)
289 if (!qflag) {
290 static const char *const names[] = {"64 bit", "32 bit"};
291 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
292 tcp->pid, names[personality]);
293 }
294#endif
295}
296#endif
Roland McGrathe10e62a2004-09-04 04:20:43 +0000297
Roland McGrath9797ceb2002-12-30 10:23:00 +0000298static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299
Roland McGrathe10e62a2004-09-04 04:20:43 +0000300static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000302 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000303 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000304 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306 { QUAL_TRACE, "trace", qual_syscall, "system call" },
307 { QUAL_TRACE, "t", qual_syscall, "system call" },
308 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
309 { QUAL_ABBREV, "a", qual_syscall, "system call" },
310 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
311 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
312 { QUAL_RAW, "raw", qual_syscall, "system call" },
313 { QUAL_RAW, "x", qual_syscall, "system call" },
314 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
315 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
316 { QUAL_SIGNAL, "s", qual_signal, "signal" },
317 { QUAL_FAULT, "fault", qual_fault, "fault" },
318 { QUAL_FAULT, "faults", qual_fault, "fault" },
319 { QUAL_FAULT, "m", qual_fault, "fault" },
320 { QUAL_READ, "read", qual_desc, "descriptor" },
321 { QUAL_READ, "reads", qual_desc, "descriptor" },
322 { QUAL_READ, "r", qual_desc, "descriptor" },
323 { QUAL_WRITE, "write", qual_desc, "descriptor" },
324 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
325 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000326 { 0, NULL, NULL, NULL },
327};
328
Roland McGrath9797ceb2002-12-30 10:23:00 +0000329static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000331{
Roland McGrath138c6a32006-01-12 09:50:49 +0000332 if (pers == 0 || pers < 0) {
333 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000334 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000335 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000336 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000337 }
338
339#if SUPPORTED_PERSONALITIES >= 2
340 if (pers == 1 || pers < 0) {
341 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000342 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000343 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000344 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000345 }
346#endif /* SUPPORTED_PERSONALITIES >= 2 */
347
348#if SUPPORTED_PERSONALITIES >= 3
349 if (pers == 2 || pers < 0) {
350 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000351 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000352 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000353 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000354 }
355#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000356}
357
358static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000359qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000360{
361 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000362 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000363
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000364 if (isdigit((unsigned char)*s)) {
365 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000366 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000367 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000368 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000369 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000370 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000371 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000372 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000373 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000375 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000376
377#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000378 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000379 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000380 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000381 rc = 0;
382 }
383#endif /* SUPPORTED_PERSONALITIES >= 2 */
384
385#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000386 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000387 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000388 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000389 rc = 0;
390 }
391#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000392
Roland McGrathfe6b3522005-02-02 04:40:11 +0000393 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394}
395
396static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000397qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000398{
399 int i;
400 char buf[32];
401
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000402 if (isdigit((unsigned char)*s)) {
403 int signo = atoi(s);
404 if (signo < 0 || signo >= MAX_QUALS)
405 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000406 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000407 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000408 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000409 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000410 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000411 strcpy(buf, s);
412 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000413 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000414 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000415 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000416 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000417 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000418 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000419 }
Roland McGrath76421df2005-02-02 03:51:18 +0000420 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000421}
422
423static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000424qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000425{
426 return -1;
427}
428
429static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000430qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000431{
Roland McGrath48a035f2006-01-12 09:45:56 +0000432 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000433 int desc = atoi(s);
434 if (desc < 0 || desc >= MAX_QUALS)
435 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000436 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000437 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 }
439 return -1;
440}
441
442static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000443lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444{
445 if (strcmp(s, "file") == 0)
446 return TRACE_FILE;
447 if (strcmp(s, "ipc") == 0)
448 return TRACE_IPC;
449 if (strcmp(s, "network") == 0)
450 return TRACE_NETWORK;
451 if (strcmp(s, "process") == 0)
452 return TRACE_PROCESS;
453 if (strcmp(s, "signal") == 0)
454 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000455 if (strcmp(s, "desc") == 0)
456 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457 return -1;
458}
459
460void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000461qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000462{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000463 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000465 char *copy;
466 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 int i, n;
468
469 opt = &qual_options[0];
470 for (i = 0; (p = qual_options[i].option_name); i++) {
471 n = strlen(p);
472 if (strncmp(s, p, n) == 0 && s[n] == '=') {
473 opt = &qual_options[i];
474 s += n + 1;
475 break;
476 }
477 }
478 not = 0;
479 if (*s == '!') {
480 not = 1;
481 s++;
482 }
483 if (strcmp(s, "none") == 0) {
484 not = 1 - not;
485 s = "all";
486 }
487 if (strcmp(s, "all") == 0) {
488 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000489 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 }
491 return;
492 }
493 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000494 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200496 copy = strdup(s);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200497 if (!copy)
498 die_out_of_memory();
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000499 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000501 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000502 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000503 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000504
505#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000506 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000507 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000508 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000509#endif /* SUPPORTED_PERSONALITIES >= 2 */
510
511#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000512 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000513 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000514 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000515#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000516
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000517 continue;
518 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000519 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520 fprintf(stderr, "strace: invalid %s `%s'\n",
521 opt->argument_name, p);
522 exit(1);
523 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000525 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000526 return;
527}
528
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000529#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000530enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000531#else /* FREEBSD */
532enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
533
534struct subcall {
535 int call;
536 int nsubcalls;
537 int subcalls[5];
538};
539
Roland McGratha4d48532005-06-08 20:45:28 +0000540static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000541 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000542#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000543 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000544#else
545 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
546#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
548};
549#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000551#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552
Roland McGratha4d48532005-06-08 20:45:28 +0000553static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200554decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000556 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200557 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000558 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 switch (style) {
561 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000562 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
563 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200565 tcp->u_nargs = n = sysent[tcp->scno].nargs;
566 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567 tcp->u_arg[i] = tcp->u_arg[i + 1];
568 break;
569 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000570 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
571 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 tcp->scno = subcall + tcp->u_arg[0];
573 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200574 tcp->u_nargs = n = sysent[tcp->scno].nargs;
575 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000576 if (size == sizeof(int)) {
577 unsigned int arg;
578 if (umove(tcp, addr, &arg) < 0)
579 arg = 0;
580 tcp->u_arg[i] = arg;
581 }
582 else if (size == sizeof(long)) {
583 unsigned long arg;
584 if (umove(tcp, addr, &arg) < 0)
585 arg = 0;
586 tcp->u_arg[i] = arg;
587 }
588 else
589 abort();
590 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592 break;
593 case mask_style:
594 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 for (i = 0; mask; i++)
596 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000597 if (i >= nsubcalls)
598 return;
599 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200601 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000603 case door_style:
604 /*
605 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000606 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000607 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000608 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
609 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000610 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200611 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000612 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000613#ifdef FREEBSD
614 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000615 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000616 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000617 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000618 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
619 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
620 for (i = 0; i < tcp->u_nargs; i++)
621 tcp->u_arg[i] = tcp->u_arg[i + 1];
622 }
623 break;
624#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 }
626}
627#endif
628
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200629int
630printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200632 if (entering(tcp)) {
633 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200635 for (i = 0; i < tcp->u_nargs; i++)
636 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
637 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638 return 0;
639}
640
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200641long
642getrval2(struct tcb *tcp)
643{
644 long val = -1;
645
646#ifdef LINUX
647#if defined (SPARC) || defined (SPARC64)
648 struct pt_regs regs;
649 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
650 return -1;
651 val = regs.u_regs[U_REG_O1];
652#elif defined(SH)
653 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
654 return -1;
655#elif defined(IA64)
656 if (upeek(tcp, PT_R9, &val) < 0)
657 return -1;
658#endif
659#endif /* LINUX */
660
661#ifdef SUNOS4
662 if (upeek(tcp, uoff(u_rval2), &val) < 0)
663 return -1;
664#endif /* SUNOS4 */
665
666#ifdef SVR4
667#ifdef SPARC
668 val = tcp->status.PR_REG[R_O1];
669#endif /* SPARC */
670#ifdef I386
671 val = tcp->status.PR_REG[EDX];
672#endif /* I386 */
673#ifdef X86_64
674 val = tcp->status.PR_REG[RDX];
675#endif /* X86_64 */
676#ifdef MIPS
677 val = tcp->status.PR_REG[CTX_V1];
678#endif /* MIPS */
679#endif /* SVR4 */
680
681#ifdef FREEBSD
682 struct reg regs;
683 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
684 val = regs.r_edx;
685#endif
686 return val;
687}
688
689#ifdef SUNOS4
690/*
691 * Apparently, indirect system calls have already be converted by ptrace(2),
692 * so if you see "indir" this program has gone astray.
693 */
694int
695sys_indir(struct tcb *tcp)
696{
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200697 int i, nargs;
698 long scno;
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200699
700 if (entering(tcp)) {
701 scno = tcp->u_arg[0];
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200702 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenkofabaa912011-08-25 01:23:10 +0200703 fprintf(stderr, "Bogus syscall: %ld\n", scno);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200704 return 0;
705 }
706 nargs = sysent[scno].nargs;
Denys Vlasenko5940e652011-09-01 09:55:05 +0200707 tprints(sysent[scno].sys_name);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200708 for (i = 0; i < nargs; i++)
709 tprintf(", %#lx", tcp->u_arg[i+1]);
710 }
711 return 0;
712}
713#endif /* SUNOS4 */
714
715int
716is_restart_error(struct tcb *tcp)
717{
718#ifdef LINUX
719 if (!syserror(tcp))
720 return 0;
721 switch (tcp->u_error) {
722 case ERESTARTSYS:
723 case ERESTARTNOINTR:
724 case ERESTARTNOHAND:
725 case ERESTART_RESTARTBLOCK:
726 return 1;
727 default:
728 break;
729 }
730#endif /* LINUX */
731 return 0;
732}
733
734struct tcb *tcp_last = NULL;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735
736#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200737# if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200738static struct pt_regs i386_regs;
739# elif defined(X86_64)
740static struct pt_regs x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200741# elif defined (IA64)
742long r8, r10, psr; /* TODO: make static? */
743long ia32 = 0; /* not static */
744# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200745static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200746# elif defined (M68K)
747static long d0;
748# elif defined(BFIN)
749static long r0;
750# elif defined (ARM)
751static struct pt_regs regs;
752# elif defined (ALPHA)
753static long r0;
754static long a3;
755# elif defined(AVR32)
756static struct pt_regs regs;
757# elif defined (SPARC) || defined (SPARC64)
758static struct pt_regs regs;
759static unsigned long trap;
760# elif defined(LINUX_MIPSN32)
761static long long a3;
762static long long r2;
763# elif defined(MIPS)
764static long a3;
765static long r2;
766# elif defined(S390) || defined(S390X)
767static long gpr2;
768static long pc;
769static long syscall_mode;
770# elif defined(HPPA)
771static long r28;
772# elif defined(SH)
773static long r0;
774# elif defined(SH64)
775static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200776# elif defined(CRISV10) || defined(CRISV32)
777static long r10;
778# elif defined(MICROBLAZE)
779static long r3;
780# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000782#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200783struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000784#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000785
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200786/* Returns:
787 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
788 * 1: ok, continue in trace_syscall().
789 * other: error, trace_syscall() should print error indicator
790 * ("????" etc) and bail out.
791 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200792#ifndef USE_PROCFS
793static
794#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000795int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200796get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000801# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000802 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200803 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000804
805 if (syscall_mode != -ENOSYS) {
806 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000807 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000808 */
809 scno = syscall_mode;
810 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000811 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000812 * Old style of "passing" the scno via the SVC instruction.
813 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000814 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200815 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200816 static const int gpr_offset[16] = {
817 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
818 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
819 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
820 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
821 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000822
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000823 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000825 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000826 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000827 if (errno) {
828 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000829 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000830 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000831
832 /*
833 * We have to check if the SVC got executed directly or via an
834 * EXECUTE instruction. In case of EXECUTE it is necessary to do
835 * instruction decoding to derive the system call number.
836 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
837 * so that this doesn't work if a SVC opcode is part of an EXECUTE
838 * opcode. Since there is no way to find out the opcode size this
839 * is the best we can do...
840 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000841 if ((opcode & 0xff00) == 0x0a00) {
842 /* SVC opcode */
843 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000844 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000845 else {
846 /* SVC got executed by EXECUTE instruction */
847
848 /*
849 * Do instruction decoding of EXECUTE. If you really want to
850 * understand this, read the Principles of Operations.
851 */
852 svc_addr = (void *) (opcode & 0xfff);
853
854 tmp = 0;
855 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000856 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000857 return -1;
858 svc_addr += tmp;
859
860 tmp = 0;
861 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000862 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000863 return -1;
864 svc_addr += tmp;
865
Denys Vlasenkofb036672009-01-23 16:30:26 +0000866 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000867 if (errno)
868 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000869# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000870 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000871# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000872 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000873# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 tmp = 0;
875 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000876 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000877 return -1;
878
879 scno = (scno | tmp) & 0xff;
880 }
881 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000882# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000883 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200885# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200886 /* TODO: speed up strace by not doing this at every syscall.
887 * We only need to do it after execve.
888 */
889 int currpers;
890 long val;
891 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200892
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200893 /* Check for 64/32 bit mode. */
894 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
895 return -1;
896 /* SF is bit 0 of MSR */
897 if (val < 0)
898 currpers = 0;
899 else
900 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000901 update_personality(tcp, currpers);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200902# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000903# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200904 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000905 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
906 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200907 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000908# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000909 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000911# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200912 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200914 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000915# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200916 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200917 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
918 return -1;
919 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000920
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200921 /* Check CS register value. On x86-64 linux it is:
922 * 0x33 for long mode (64 bit)
923 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200924 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200925 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200926 case 0x23: currpers = 1; break;
927 case 0x33: currpers = 0; break;
928 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200929 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200931 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200932 currpers = current_personality;
933 break;
934 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000935# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200936 /* This version analyzes the opcode of a syscall instruction.
937 * (int 0x80 on i386 vs. syscall on x86-64)
938 * It works, but is too complicated.
939 */
940 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000941
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200942 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000943
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200944 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
945 rip -= 2;
946 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000947
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200948 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200949 if (errno)
950 fprintf(stderr, "ptrace_peektext failed: %s\n",
951 strerror(errno));
952 switch (call & 0xffff) {
953 /* x86-64: syscall = 0x0f 0x05 */
954 case 0x050f: currpers = 0; break;
955 /* i386: int 0x80 = 0xcd 0x80 */
956 case 0x80cd: currpers = 1; break;
957 default:
958 currpers = current_personality;
959 fprintf(stderr,
960 "Unknown syscall opcode (0x%04X) while "
961 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200962 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200963 break;
964 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000965# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000966 update_personality(tcp, currpers);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000967# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000968# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200969 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000970 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200971 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200972 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200973 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000974 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200975 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000976 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200977 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000978# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200979 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000980 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000981 return -1;
982
983 /*
984 * We only need to grab the syscall number on syscall entry.
985 */
986 if (regs.ARM_ip == 0) {
987 /*
988 * Note: we only deal with only 32-bit CPUs here.
989 */
990 if (regs.ARM_cpsr & 0x20) {
991 /*
992 * Get the Thumb-mode system call number
993 */
994 scno = regs.ARM_r7;
995 } else {
996 /*
997 * Get the ARM-mode system call number
998 */
999 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001000 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001001 if (errno)
1002 return -1;
1003
Roland McGrathf691bd22006-04-25 07:34:41 +00001004 /* Handle the EABI syscall convention. We do not
1005 bother converting structures between the two
1006 ABIs, but basic functionality should work even
1007 if strace and the traced program have different
1008 ABIs. */
1009 if (scno == 0xef000000) {
1010 scno = regs.ARM_r7;
1011 } else {
1012 if ((scno & 0x0ff00000) != 0x0f900000) {
1013 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1014 scno);
1015 return -1;
1016 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001017
Roland McGrathf691bd22006-04-25 07:34:41 +00001018 /*
1019 * Fixup the syscall number
1020 */
1021 scno &= 0x000fffff;
1022 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 }
Roland McGrath56703312008-05-20 01:35:55 +00001024 if (scno & 0x0f0000) {
1025 /*
1026 * Handle ARM specific syscall
1027 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001028 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +00001029 scno &= 0x0000ffff;
1030 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001031 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001032
Roland McGrath0f87c492003-06-03 23:29:04 +00001033 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001034 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1035 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001037# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001038 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001040# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001041 unsigned long long regs[38];
1042
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001043 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001044 return -1;
1045 a3 = regs[REG_A3];
1046 r2 = regs[REG_V0];
1047
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001048 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001049 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001050 if (a3 == 0 || a3 == -1) {
1051 if (debug)
1052 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001053 return 0;
1054 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001055 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001056# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001057 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001058 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001059 if (upeek(tcp, REG_V0, &scno) < 0)
1060 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001061
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001062 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 if (a3 == 0 || a3 == -1) {
1064 if (debug)
1065 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001066 return 0;
1067 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001068 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001069# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001070 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001072 if (upeek(tcp, REG_R0, &scno) < 0)
1073 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001075 /*
1076 * Do some sanity checks to figure out if it's
1077 * really a syscall entry
1078 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001079 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001080 if (a3 == 0 || a3 == -1) {
1081 if (debug)
1082 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return 0;
1084 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001086# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001088 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 return -1;
1090
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001091 /* Disassemble the syscall trap. */
1092 /* Retrieve the syscall trap instruction. */
1093 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001094# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001095 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1096 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001097# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001098 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001099# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001100 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001101 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001102
1103 /* Disassemble the trap to see what personality to use. */
1104 switch (trap) {
1105 case 0x91d02010:
1106 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001107 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001108 break;
1109 case 0x91d0206d:
1110 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001111 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001112 break;
1113 case 0x91d02000:
1114 /* SunOS syscall trap. (pers 1) */
1115 fprintf(stderr, "syscall: SunOS no support\n");
1116 return -1;
1117 case 0x91d02008:
1118 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001119 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001120 break;
1121 case 0x91d02009:
1122 /* NetBSD/FreeBSD syscall trap. */
1123 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1124 return -1;
1125 case 0x91d02027:
1126 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001127 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001128 break;
1129 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001130# if defined (SPARC64)
1131 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1132# else
1133 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1134# endif
1135 return -1;
1136 }
1137
1138 /* Extract the system call number from the registers. */
1139 if (trap == 0x91d02027)
1140 scno = 156;
1141 else
1142 scno = regs.u_regs[U_REG_G1];
1143 if (scno == 0) {
1144 scno = regs.u_regs[U_REG_O0];
1145 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1146 }
1147# elif defined(HPPA)
1148 if (upeek(tcp, PT_GR20, &scno) < 0)
1149 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001150# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001151 /*
1152 * In the new syscall ABI, the system call number is in R3.
1153 */
1154 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1155 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001156
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001157 if (scno < 0) {
1158 /* Odd as it may seem, a glibc bug has been known to cause
1159 glibc to issue bogus negative syscall numbers. So for
1160 our purposes, make strace print what it *should* have been */
1161 long correct_scno = (scno & 0xff);
1162 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001163 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001164 "Detected glibc bug: bogus system call"
1165 " number = %ld, correcting to %ld\n",
1166 scno,
1167 correct_scno);
1168 scno = correct_scno;
1169 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001170# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001171 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001172 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001173 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# elif defined(CRISV10) || defined(CRISV32)
1175 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1176 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001177# elif defined(TILE)
1178 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1179 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001180# elif defined(MICROBLAZE)
1181 if (upeek(tcp, 0, &scno) < 0)
1182 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001183# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001185
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001187 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001189#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001190 /* new syscall ABI returns result in R0 */
1191 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1192 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001193#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001194 /* ABI defines result returned in r9 */
1195 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1196 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001198
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001199#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001200# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001201 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202# else
1203# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001204 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001205# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001206 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001207 perror("pread");
1208 return -1;
1209 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210 switch (regs.r_eax) {
1211 case SYS_syscall:
1212 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1214 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001215 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001216 scno = regs.r_eax;
1217 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001218 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001219# endif /* FREEBSD */
1220# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001221#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001222
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001223 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001224 return 1;
1225}
1226
Roland McGrath17352792005-06-07 23:21:26 +00001227long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001228known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001229{
1230 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001231#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001232 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001233 scno = sysent[scno].native_scno;
1234 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001235#endif
Roland McGrath17352792005-06-07 23:21:26 +00001236 scno += NR_SYSCALL_BASE;
1237 return scno;
1238}
1239
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001240/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001241 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001242 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001243 * 1: ok, continue in trace_syscall().
1244 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001245 * ("????" etc) and bail out.
1246 */
Roland McGratha4d48532005-06-08 20:45:28 +00001247static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001248syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001249{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001251 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001252
Denys Vlasenkoece98792011-08-25 10:25:35 +02001253 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1254 if (
1255 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001257 || scno == SYS_vfork
1258#endif
John Hughes4e36a812001-04-18 15:11:51 +00001259#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001260 || scno == SYS_fork1
1261#endif
John Hughes4e36a812001-04-18 15:11:51 +00001262#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001263 || scno == SYS_forkall
1264#endif
John Hughes4e36a812001-04-18 15:11:51 +00001265#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001266 || scno == SYS_rfork1
1267#endif
John Hughes4e36a812001-04-18 15:11:51 +00001268#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001269 || scno == SYS_rforkall
1270#endif
1271 ) {
1272 /* We are returning in the child, fake it. */
1273 tcp->status.PR_WHY = PR_SYSENTRY;
1274 trace_syscall(tcp);
1275 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001277 else {
1278 fprintf(stderr, "syscall: missing entry\n");
1279 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280 }
1281 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001282#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001283
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001285 if (scno == 0) {
1286 fprintf(stderr, "syscall: missing entry\n");
1287 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001288 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001289#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001290
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001292 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001294 if (i386_regs.eax != -ENOSYS) {
1295 if (debug)
1296 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1297 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001299#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001300 {
1301 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001302 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001303 rax = (int)rax; /* sign extend from 32 bits */
1304 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001305 if (debug)
1306 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1307 return 0;
1308 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001309 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001310#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001311 /* TODO: we already fetched PT_GPR2 in get_scno
1312 * and stored it in syscall_mode, reuse it here
1313 * instead of re-fetching?
1314 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001315 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001316 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001317 if (syscall_mode != -ENOSYS)
1318 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001319 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001320 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001321 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001322 return 0;
1323 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001325 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001326 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001328 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001330 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001331 return 0;
1332 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001333#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001334 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001335 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001336 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001337 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001338 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001339 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001340 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001341 return 0;
1342 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001343#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001344 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001346 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001347 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001348 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349 return 0;
1350 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001351#elif defined(MICROBLAZE)
1352 if (upeek(tcp, 3 * 4, &r3) < 0)
1353 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001354 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001355 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001356 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001357 return 0;
1358 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359#endif
1360#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001361 return 1;
1362}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001364static int
1365internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001366{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001367 /*
1368 * We must always trace a few critical system calls in order to
1369 * correctly support following forks in the presence of tracing
1370 * qualifiers.
1371 */
1372 int (*func)();
1373
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001374 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001375 return 0;
1376
1377 func = sysent[tcp->scno].sys_func;
1378
1379 if ( sys_fork == func
1380#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1381 || sys_vfork == func
1382#endif
1383#ifdef LINUX
1384 || sys_clone == func
1385#endif
1386#if UNIXWARE > 2
1387 || sys_rfork == func
1388#endif
1389 )
1390 return internal_fork(tcp);
1391
1392#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1393 if ( sys_execve == func
1394# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1395 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001396# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001397# if UNIXWARE > 2
1398 || sys_rexecve == func
1399# endif
1400 )
1401 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001402#endif
1403
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001404 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001405}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406
Roland McGratha4d48532005-06-08 20:45:28 +00001407static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001408syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001409{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001410#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001411 int i, nargs;
1412
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001413 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001414 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001415 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001416 nargs = tcp->u_nargs = MAX_ARGS;
1417
1418# if defined(S390) || defined(S390X)
1419 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001420 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1421 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001422# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001423 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001424 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1425 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426# elif defined(IA64)
1427 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001428 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001429 long rbs_end;
1430 /* be backwards compatible with kernel < 2.4.4... */
1431# ifndef PT_RBS_END
1432# define PT_RBS_END PT_AR_BSP
1433# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001434
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001435 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1436 return -1;
1437 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001438 return -1;
1439
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001440 sof = (cfm >> 0) & 0x7f;
1441 sol = (cfm >> 7) & 0x7f;
1442 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1443
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001444 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001445 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1446 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1447 return -1;
1448 }
1449 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001450 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1451 PT_R9 /* ECX = out1 */,
1452 PT_R10 /* EDX = out2 */,
1453 PT_R14 /* ESI = out3 */,
1454 PT_R15 /* EDI = out4 */,
1455 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001456
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001457 for (i = 0; i < nargs; ++i) {
1458 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1459 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001460 /* truncate away IVE sign-extension */
1461 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001462 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001463 }
1464# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1465 /* N32 and N64 both use up to six registers. */
1466 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001467
1468 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1469 return -1;
1470
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001471 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001472 tcp->u_arg[i] = regs[REG_A0 + i];
1473# if defined(LINUX_MIPSN32)
1474 tcp->ext_arg[i] = regs[REG_A0 + i];
1475# endif
1476 }
1477# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001478 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001479 long sp;
1480
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001481 if (upeek(tcp, REG_SP, &sp) < 0)
1482 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001483 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001484 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1485 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001486 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001487 (char *)(tcp->u_arg + 4));
1488 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001489 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001490 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001491 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001493# elif defined(POWERPC)
1494# ifndef PT_ORIG_R3
1495# define PT_ORIG_R3 34
1496# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001497 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001498 if (upeek(tcp, (i==0) ?
1499 (sizeof(unsigned long) * PT_ORIG_R3) :
1500 ((i+PT_R3) * sizeof(unsigned long)),
1501 &tcp->u_arg[i]) < 0)
1502 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001503 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001504# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001505 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001506 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1507# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001508 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001509 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1510 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001511# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001512 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001513 tcp->u_arg[i] = regs.uregs[i];
1514# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001515 (void)i;
1516 (void)nargs;
1517 tcp->u_arg[0] = regs.r12;
1518 tcp->u_arg[1] = regs.r11;
1519 tcp->u_arg[2] = regs.r10;
1520 tcp->u_arg[3] = regs.r9;
1521 tcp->u_arg[4] = regs.r5;
1522 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001523# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001524 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 +02001525
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001526 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001527 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1528 return -1;
1529# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001530 static const int syscall_regs[MAX_ARGS] = {
1531 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1532 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001533 };
1534
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001535 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001536 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001537 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001538# elif defined(SH64)
1539 int i;
1540 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001541 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001542
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001543 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001544 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1545 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001546# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001547 (void)i;
1548 (void)nargs;
1549 if (current_personality == 0) { /* x86-64 ABI */
1550 tcp->u_arg[0] = x86_64_regs.rdi;
1551 tcp->u_arg[1] = x86_64_regs.rsi;
1552 tcp->u_arg[2] = x86_64_regs.rdx;
1553 tcp->u_arg[3] = x86_64_regs.r10;
1554 tcp->u_arg[4] = x86_64_regs.r8;
1555 tcp->u_arg[5] = x86_64_regs.r9;
1556 } else { /* i386 ABI */
1557 /* Sign-extend lower 32 bits */
1558 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1559 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1560 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1561 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1562 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1563 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1564 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001565# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001566 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001567 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1568 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001569# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001570 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001571 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001572 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001573 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001574
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001575 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001576 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1577 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001578# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001579 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001580 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1581 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001582# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001583 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001584 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1585 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001586# elif defined(I386)
1587 (void)i;
1588 (void)nargs;
1589 tcp->u_arg[0] = i386_regs.ebx;
1590 tcp->u_arg[1] = i386_regs.ecx;
1591 tcp->u_arg[2] = i386_regs.edx;
1592 tcp->u_arg[3] = i386_regs.esi;
1593 tcp->u_arg[4] = i386_regs.edi;
1594 tcp->u_arg[5] = i386_regs.ebp;
1595# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001596 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001597 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1598 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001599# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001600#endif /* LINUX */
1601#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001602 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001603 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001604 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001605 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001606 nargs = tcp->u_nargs = MAX_ARGS;
1607 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001608 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001610 if (upeek(tcp, uoff(u_arg[0]) +
1611 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1612 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 }
1614#endif /* SUNOS4 */
1615#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001616# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 /*
1618 * SGI is broken: even though it has pr_sysarg, it doesn't
1619 * set them on system call entry. Get a clue.
1620 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001621 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 tcp->u_nargs = sysent[tcp->scno].nargs;
1623 else
1624 tcp->u_nargs = tcp->status.pr_nsysarg;
1625 if (tcp->u_nargs > 4) {
1626 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001627 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001629 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 }
1631 else {
1632 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001633 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001635# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001636 /*
1637 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1638 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001639 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001640 tcp->u_nargs = sysent[tcp->scno].nargs;
1641 else
1642 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1643 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001644 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1645# elif defined(HAVE_PR_SYSCALL)
1646 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001647 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 tcp->u_nargs = sysent[tcp->scno].nargs;
1649 else
1650 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001651 for (i = 0; i < tcp->u_nargs; i++)
1652 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1653# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001654 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 tcp->u_nargs = sysent[tcp->scno].nargs;
1656 else
1657 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001658 if (tcp->u_nargs > 0)
1659 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001660 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1661# else
John Hughes25299712001-03-06 10:10:06 +00001662 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001663# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001665#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001666 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001667 sysent[tcp->scno].nargs > tcp->status.val)
1668 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001669 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001670 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001671 if (tcp->u_nargs < 0)
1672 tcp->u_nargs = 0;
1673 if (tcp->u_nargs > MAX_ARGS)
1674 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001675 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001676 case SYS___syscall:
1677 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1678 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001679 break;
1680 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001681 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1682 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001683 break;
1684 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001685 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1686 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001687 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001688 }
1689#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001690 return 1;
1691}
1692
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001693static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001694trace_syscall_entering(struct tcb *tcp)
1695{
1696 int res, scno_good;
1697
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001698#if defined TCB_WAITEXECVE
1699 if (tcp->flags & TCB_WAITEXECVE) {
1700 /* This is the post-execve SIGTRAP. */
1701 tcp->flags &= ~TCB_WAITEXECVE;
1702 return 0;
1703 }
1704#endif
1705
Denys Vlasenko06602d92011-08-24 17:53:52 +02001706 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001707 if (res == 0)
1708 return res;
1709 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001710 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001711 if (res == 0)
1712 return res;
1713 if (res == 1)
1714 res = syscall_enter(tcp);
1715 if (res == 0)
1716 return res;
1717
1718 if (res != 1) {
1719 printleader(tcp);
1720 tcp->flags &= ~TCB_REPRINT;
1721 tcp_last = tcp;
1722 if (scno_good != 1)
1723 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001724 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001725 tprintf("syscall_%lu(", tcp->scno);
1726 else
1727 tprintf("%s(", sysent[tcp->scno].sys_name);
1728 /*
1729 * " <unavailable>" will be added later by the code which
1730 * detects ptrace errors.
1731 */
1732 goto ret;
1733 }
1734
1735 switch (known_scno(tcp)) {
1736#ifdef SYS_socket_subcall
1737 case SYS_socketcall:
1738 decode_subcall(tcp, SYS_socket_subcall,
1739 SYS_socket_nsubcalls, deref_style);
1740 break;
1741#endif
1742#ifdef SYS_ipc_subcall
1743 case SYS_ipc:
1744 decode_subcall(tcp, SYS_ipc_subcall,
1745 SYS_ipc_nsubcalls, shift_style);
1746 break;
1747#endif
1748#ifdef SVR4
1749#ifdef SYS_pgrpsys_subcall
1750 case SYS_pgrpsys:
1751 decode_subcall(tcp, SYS_pgrpsys_subcall,
1752 SYS_pgrpsys_nsubcalls, shift_style);
1753 break;
1754#endif /* SYS_pgrpsys_subcall */
1755#ifdef SYS_sigcall_subcall
1756 case SYS_sigcall:
1757 decode_subcall(tcp, SYS_sigcall_subcall,
1758 SYS_sigcall_nsubcalls, mask_style);
1759 break;
1760#endif /* SYS_sigcall_subcall */
1761 case SYS_msgsys:
1762 decode_subcall(tcp, SYS_msgsys_subcall,
1763 SYS_msgsys_nsubcalls, shift_style);
1764 break;
1765 case SYS_shmsys:
1766 decode_subcall(tcp, SYS_shmsys_subcall,
1767 SYS_shmsys_nsubcalls, shift_style);
1768 break;
1769 case SYS_semsys:
1770 decode_subcall(tcp, SYS_semsys_subcall,
1771 SYS_semsys_nsubcalls, shift_style);
1772 break;
1773 case SYS_sysfs:
1774 decode_subcall(tcp, SYS_sysfs_subcall,
1775 SYS_sysfs_nsubcalls, shift_style);
1776 break;
1777 case SYS_spcall:
1778 decode_subcall(tcp, SYS_spcall_subcall,
1779 SYS_spcall_nsubcalls, shift_style);
1780 break;
1781#ifdef SYS_context_subcall
1782 case SYS_context:
1783 decode_subcall(tcp, SYS_context_subcall,
1784 SYS_context_nsubcalls, shift_style);
1785 break;
1786#endif /* SYS_context_subcall */
1787#ifdef SYS_door_subcall
1788 case SYS_door:
1789 decode_subcall(tcp, SYS_door_subcall,
1790 SYS_door_nsubcalls, door_style);
1791 break;
1792#endif /* SYS_door_subcall */
1793#ifdef SYS_kaio_subcall
1794 case SYS_kaio:
1795 decode_subcall(tcp, SYS_kaio_subcall,
1796 SYS_kaio_nsubcalls, shift_style);
1797 break;
1798#endif
1799#endif /* SVR4 */
1800#ifdef FREEBSD
1801 case SYS_msgsys:
1802 case SYS_shmsys:
1803 case SYS_semsys:
1804 decode_subcall(tcp, 0, 0, table_style);
1805 break;
1806#endif
1807#ifdef SUNOS4
1808 case SYS_semsys:
1809 decode_subcall(tcp, SYS_semsys_subcall,
1810 SYS_semsys_nsubcalls, shift_style);
1811 break;
1812 case SYS_msgsys:
1813 decode_subcall(tcp, SYS_msgsys_subcall,
1814 SYS_msgsys_nsubcalls, shift_style);
1815 break;
1816 case SYS_shmsys:
1817 decode_subcall(tcp, SYS_shmsys_subcall,
1818 SYS_shmsys_nsubcalls, shift_style);
1819 break;
1820#endif
1821 }
1822
1823 internal_syscall(tcp);
1824
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001825 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001826 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1827 (tracing_paths && !pathtrace_match(tcp))) {
1828 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1829 return 0;
1830 }
1831
1832 tcp->flags &= ~TCB_FILTERED;
1833
1834 if (cflag == CFLAG_ONLY_STATS) {
1835 res = 0;
1836 goto ret;
1837 }
1838
1839 printleader(tcp);
1840 tcp->flags &= ~TCB_REPRINT;
1841 tcp_last = tcp;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001842 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001843 tprintf("syscall_%lu(", tcp->scno);
1844 else
1845 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001846 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001847 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1848 sysent[tcp->scno].sys_func != sys_exit))
1849 res = printargs(tcp);
1850 else
1851 res = (*sysent[tcp->scno].sys_func)(tcp);
1852
1853 if (fflush(tcp->outf) == EOF)
1854 return -1;
1855 ret:
1856 tcp->flags |= TCB_INSYSCALL;
1857 /* Measure the entrance time as late as possible to avoid errors. */
1858 if (dtime || cflag)
1859 gettimeofday(&tcp->etime, NULL);
1860 return res;
1861}
1862
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001863/* Returns:
1864 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1865 * 1: ok, continue in trace_syscall().
1866 * other: error, trace_syscall() should print error indicator
1867 * ("????" etc) and bail out.
1868 */
1869static int
1870get_syscall_result(struct tcb *tcp)
1871{
1872#ifdef LINUX
1873# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001874 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1875 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001876# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001877# define SO_MASK 0x10000000
1878 {
1879 long flags;
1880 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1881 return -1;
1882 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1883 return -1;
1884 if (flags & SO_MASK)
1885 result = -result;
1886 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001887# elif defined(AVR32)
1888 /* Read complete register set in one go. */
1889 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1890 return -1;
1891# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001892 if (upeek(tcp, PT_R0, &r0) < 0)
1893 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001894# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001895 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001896 return -1;
1897# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001898 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001899 return -1;
1900# elif defined(IA64)
1901# define IA64_PSR_IS ((long)1 << 34)
1902 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1903 ia32 = (psr & IA64_PSR_IS) != 0;
1904 if (upeek(tcp, PT_R8, &r8) < 0)
1905 return -1;
1906 if (upeek(tcp, PT_R10, &r10) < 0)
1907 return -1;
1908# elif defined (ARM)
1909 /* Read complete register set in one go. */
1910 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1911 return -1;
1912# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001913 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1914 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001915# elif defined (LINUX_MIPSN32)
1916 unsigned long long regs[38];
1917
1918 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1919 return -1;
1920 a3 = regs[REG_A3];
1921 r2 = regs[REG_V0];
1922# elif defined (MIPS)
1923 if (upeek(tcp, REG_A3, &a3) < 0)
1924 return -1;
1925 if (upeek(tcp, REG_V0, &r2) < 0)
1926 return -1;
1927# elif defined (ALPHA)
1928 if (upeek(tcp, REG_A3, &a3) < 0)
1929 return -1;
1930 if (upeek(tcp, REG_R0, &r0) < 0)
1931 return -1;
1932# elif defined (SPARC) || defined (SPARC64)
1933 /* Everything we need is in the current register set. */
1934 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1935 return -1;
1936# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001937 if (upeek(tcp, PT_GR28, &r28) < 0)
1938 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001939# elif defined(SH)
1940# elif defined(SH64)
1941# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001942 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1943 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001944# elif defined(TILE)
1945# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001946 if (upeek(tcp, 3 * 4, &r3) < 0)
1947 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001948# endif
1949#endif /* LINUX */
1950
1951#ifdef SUNOS4
1952#elif defined(SH)
1953 /* new syscall ABI returns result in R0 */
1954 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1955 return -1;
1956#elif defined(SH64)
1957 /* ABI defines result returned in r9 */
1958 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1959 return -1;
1960#endif
1961
1962#ifdef USE_PROCFS
1963# ifndef HAVE_PR_SYSCALL
1964# ifdef FREEBSD
1965 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1966 perror("pread");
1967 return -1;
1968 }
1969# endif /* FREEBSD */
1970# endif /* !HAVE_PR_SYSCALL */
1971#endif /* USE_PROCFS */
1972
1973 return 1;
1974}
1975
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001976/* Called at each syscall exit.
1977 * Returns:
1978 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1979 * 1: ok, continue in trace_syscall().
1980 * other: error, trace_syscall() should print error indicator
1981 * ("????" etc) and bail out.
1982 */
1983static int
1984syscall_fixup_on_sysexit(struct tcb *tcp)
1985{
1986#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001987 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1988 fprintf(stderr, "syscall: missing exit\n");
1989 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001990 }
1991#endif /* USE_PROCFS */
1992
1993#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001994 {
1995 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001996 if (scno != 0) {
1997 if (debug) {
1998 /*
1999 * This happens when a signal handler
2000 * for a signal which interrupted a
2001 * a system call makes another system call.
2002 */
2003 fprintf(stderr, "syscall: missing exit\n");
2004 }
2005 tcp->flags &= ~TCB_INSYSCALL;
2006 }
2007 }
2008#endif /* SUNOS4 */
2009
2010#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002011# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002012 if (syscall_mode != -ENOSYS)
2013 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002014 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002015 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2016 /*
2017 * Return from execve.
2018 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2019 * flag set for the post-execve SIGTRAP to see and reset.
2020 */
2021 gpr2 = 0;
2022 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002023# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002024#endif /* LINUX */
2025 return 1;
2026}
2027
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002028#ifdef LINUX
2029/*
2030 * Check the syscall return value register value for whether it is
2031 * a negated errno code indicating an error, or a success return value.
2032 */
2033static inline int
2034is_negated_errno(unsigned long int val)
2035{
2036 unsigned long int max = -(long int) nerrnos;
2037# if SUPPORTED_PERSONALITIES > 1
2038 if (personality_wordsize[current_personality] < sizeof(val)) {
2039 val = (unsigned int) val;
2040 max = (unsigned int) max;
2041 }
2042# endif
2043 return val > max;
2044}
2045#endif
2046
2047static int
2048get_error(struct tcb *tcp)
2049{
2050 int u_error = 0;
2051#ifdef LINUX
2052 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002053 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002054 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2055 check_errno = 0;
2056 }
2057# if defined(S390) || defined(S390X)
2058 if (check_errno && is_negated_errno(gpr2)) {
2059 tcp->u_rval = -1;
2060 u_error = -gpr2;
2061 }
2062 else {
2063 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002064 }
2065# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002066 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002067 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002068 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002069 }
2070 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002071 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002072 }
2073# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002074 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002075 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002076 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002077 }
2078 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002079 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002080 }
2081# elif defined(IA64)
2082 if (ia32) {
2083 int err;
2084
2085 err = (int)r8;
2086 if (check_errno && is_negated_errno(err)) {
2087 tcp->u_rval = -1;
2088 u_error = -err;
2089 }
2090 else {
2091 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002092 }
2093 } else {
2094 if (check_errno && r10) {
2095 tcp->u_rval = -1;
2096 u_error = r8;
2097 } else {
2098 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002099 }
2100 }
2101# elif defined(MIPS)
2102 if (check_errno && a3) {
2103 tcp->u_rval = -1;
2104 u_error = r2;
2105 } else {
2106 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002107 }
2108# elif defined(POWERPC)
2109 if (check_errno && is_negated_errno(result)) {
2110 tcp->u_rval = -1;
2111 u_error = -result;
2112 }
2113 else {
2114 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002115 }
2116# elif defined(M68K)
2117 if (check_errno && is_negated_errno(d0)) {
2118 tcp->u_rval = -1;
2119 u_error = -d0;
2120 }
2121 else {
2122 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002123 }
2124# elif defined(ARM)
2125 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2126 tcp->u_rval = -1;
2127 u_error = -regs.ARM_r0;
2128 }
2129 else {
2130 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002131 }
2132# elif defined(AVR32)
2133 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2134 tcp->u_rval = -1;
2135 u_error = -regs.r12;
2136 }
2137 else {
2138 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002139 }
2140# elif defined(BFIN)
2141 if (check_errno && is_negated_errno(r0)) {
2142 tcp->u_rval = -1;
2143 u_error = -r0;
2144 } else {
2145 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002146 }
2147# elif defined(ALPHA)
2148 if (check_errno && a3) {
2149 tcp->u_rval = -1;
2150 u_error = r0;
2151 }
2152 else {
2153 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002154 }
2155# elif defined(SPARC)
2156 if (check_errno && regs.psr & PSR_C) {
2157 tcp->u_rval = -1;
2158 u_error = regs.u_regs[U_REG_O0];
2159 }
2160 else {
2161 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002162 }
2163# elif defined(SPARC64)
2164 if (check_errno && regs.tstate & 0x1100000000UL) {
2165 tcp->u_rval = -1;
2166 u_error = regs.u_regs[U_REG_O0];
2167 }
2168 else {
2169 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002170 }
2171# elif defined(HPPA)
2172 if (check_errno && is_negated_errno(r28)) {
2173 tcp->u_rval = -1;
2174 u_error = -r28;
2175 }
2176 else {
2177 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002178 }
2179# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002180 if (check_errno && is_negated_errno(r0)) {
2181 tcp->u_rval = -1;
2182 u_error = -r0;
2183 }
2184 else {
2185 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002186 }
2187# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002188 if (check_errno && is_negated_errno(r9)) {
2189 tcp->u_rval = -1;
2190 u_error = -r9;
2191 }
2192 else {
2193 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002194 }
2195# elif defined(CRISV10) || defined(CRISV32)
2196 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2197 tcp->u_rval = -1;
2198 u_error = -r10;
2199 }
2200 else {
2201 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002202 }
2203# elif defined(TILE)
2204 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002205 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2206 return -1;
2207 if (check_errno && rval < 0 && rval > -nerrnos) {
2208 tcp->u_rval = -1;
2209 u_error = -rval;
2210 }
2211 else {
2212 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002213 }
2214# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002215 if (check_errno && is_negated_errno(r3)) {
2216 tcp->u_rval = -1;
2217 u_error = -r3;
2218 }
2219 else {
2220 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002221 }
2222# endif
2223#endif /* LINUX */
2224#ifdef SUNOS4
2225 /* get error code from user struct */
2226 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2227 return -1;
2228 u_error >>= 24; /* u_error is a char */
2229
2230 /* get system call return value */
2231 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2232 return -1;
2233#endif /* SUNOS4 */
2234#ifdef SVR4
2235# ifdef SPARC
2236 /* Judicious guessing goes a long way. */
2237 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2238 tcp->u_rval = -1;
2239 u_error = tcp->status.pr_reg[R_O0];
2240 }
2241 else {
2242 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002243 }
2244# endif /* SPARC */
2245# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002246 if (tcp->status.PR_REG[EFL] & 0x1) {
2247 tcp->u_rval = -1;
2248 u_error = tcp->status.PR_REG[EAX];
2249 }
2250 else {
2251 tcp->u_rval = tcp->status.PR_REG[EAX];
2252# ifdef HAVE_LONG_LONG
2253 tcp->u_lrval =
2254 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2255 tcp->status.PR_REG[EAX];
2256# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002257 }
2258# endif /* I386 */
2259# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002260 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2261 tcp->u_rval = -1;
2262 u_error = tcp->status.PR_REG[RAX];
2263 }
2264 else {
2265 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002266 }
2267# endif /* X86_64 */
2268# ifdef MIPS
2269 if (tcp->status.pr_reg[CTX_A3]) {
2270 tcp->u_rval = -1;
2271 u_error = tcp->status.pr_reg[CTX_V0];
2272 }
2273 else {
2274 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002275 }
2276# endif /* MIPS */
2277#endif /* SVR4 */
2278#ifdef FREEBSD
2279 if (regs.r_eflags & PSL_C) {
2280 tcp->u_rval = -1;
2281 u_error = regs.r_eax;
2282 } else {
2283 tcp->u_rval = regs.r_eax;
2284 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002285 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002286 }
2287#endif /* FREEBSD */
2288 tcp->u_error = u_error;
2289 return 1;
2290}
2291
2292static void
2293dumpio(struct tcb *tcp)
2294{
2295 if (syserror(tcp))
2296 return;
2297 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2298 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002299 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002300 return;
2301 if (sysent[tcp->scno].sys_func == printargs)
2302 return;
2303 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2304 if (sysent[tcp->scno].sys_func == sys_read ||
2305 sysent[tcp->scno].sys_func == sys_pread ||
2306 sysent[tcp->scno].sys_func == sys_pread64 ||
2307 sysent[tcp->scno].sys_func == sys_recv ||
2308 sysent[tcp->scno].sys_func == sys_recvfrom)
2309 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2310 else if (sysent[tcp->scno].sys_func == sys_readv)
2311 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2312 return;
2313 }
2314 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2315 if (sysent[tcp->scno].sys_func == sys_write ||
2316 sysent[tcp->scno].sys_func == sys_pwrite ||
2317 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2318 sysent[tcp->scno].sys_func == sys_send ||
2319 sysent[tcp->scno].sys_func == sys_sendto)
2320 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2321 else if (sysent[tcp->scno].sys_func == sys_writev)
2322 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2323 return;
2324 }
2325}
2326
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002327static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002328trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002329{
2330 int sys_res;
2331 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002332 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002333 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002334
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 /* Measure the exit time as early as possible to avoid errors. */
2336 if (dtime || cflag)
2337 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00002339#if SUPPORTED_PERSONALITIES > 1
2340 update_personality(tcp, tcp->currpers);
2341#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002342 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002343 if (res == 0)
2344 return res;
2345 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002346 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002347 if (res == 0)
2348 return res;
2349 if (res == 1)
2350 res = get_error(tcp);
2351 if (res == 0)
2352 return res;
2353 if (res == 1)
2354 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002355
Grant Edwards8a082772011-04-07 20:25:40 +00002356 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002357 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002358 }
2359
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002360 if (tcp->flags & TCB_REPRINT) {
2361 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002362 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002363 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002364 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002365 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002366 }
2367
2368 if (cflag) {
2369 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002370 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002371 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002372 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002373 }
2374 }
2375
2376 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002377 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002378 tabto();
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002379 tprints("= ? <unavailable>");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002380 printtrailer();
2381 tcp->flags &= ~TCB_INSYSCALL;
2382 return res;
2383 }
2384
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002385 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002386 || (qual_flags[tcp->scno] & QUAL_RAW))
2387 sys_res = printargs(tcp);
2388 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002389 /* FIXME: not_failing_only (IOW, option -z) is broken:
2390 * failure of syscall is known only after syscall return.
2391 * Thus we end up with something like this on, say, ENOENT:
2392 * open("doesnt_exist", O_RDONLY <unfinished ...>
2393 * {next syscall decode}
2394 * whereas the intended result is that open(...) line
2395 * is not shown at all.
2396 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002397 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002398 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002399 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2400 }
2401
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002402 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002403 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002404 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002405 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002406 qual_flags[tcp->scno] & QUAL_RAW) {
2407 if (u_error)
2408 tprintf("= -1 (errno %ld)", u_error);
2409 else
2410 tprintf("= %#lx", tcp->u_rval);
2411 }
2412 else if (!(sys_res & RVAL_NONE) && u_error) {
2413 switch (u_error) {
2414#ifdef LINUX
2415 case ERESTARTSYS:
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002416 tprints("= ? ERESTARTSYS (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002417 break;
2418 case ERESTARTNOINTR:
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002419 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002420 break;
2421 case ERESTARTNOHAND:
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002422 tprints("= ? ERESTARTNOHAND (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002423 break;
2424 case ERESTART_RESTARTBLOCK:
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002425 tprints("= ? ERESTART_RESTARTBLOCK (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002426 break;
2427#endif /* LINUX */
2428 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002429 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002430 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002431 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002432 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002433 strerror(u_error));
2434 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002435 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002436 strerror(u_error));
2437 break;
2438 }
2439 if ((sys_res & RVAL_STR) && tcp->auxstr)
2440 tprintf(" (%s)", tcp->auxstr);
2441 }
2442 else {
2443 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002444 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002445 else {
2446 switch (sys_res & RVAL_MASK) {
2447 case RVAL_HEX:
2448 tprintf("= %#lx", tcp->u_rval);
2449 break;
2450 case RVAL_OCTAL:
2451 tprintf("= %#lo", tcp->u_rval);
2452 break;
2453 case RVAL_UDECIMAL:
2454 tprintf("= %lu", tcp->u_rval);
2455 break;
2456 case RVAL_DECIMAL:
2457 tprintf("= %ld", tcp->u_rval);
2458 break;
2459#ifdef HAVE_LONG_LONG
2460 case RVAL_LHEX:
2461 tprintf("= %#llx", tcp->u_lrval);
2462 break;
2463 case RVAL_LOCTAL:
2464 tprintf("= %#llo", tcp->u_lrval);
2465 break;
2466 case RVAL_LUDECIMAL:
2467 tprintf("= %llu", tcp->u_lrval);
2468 break;
2469 case RVAL_LDECIMAL:
2470 tprintf("= %lld", tcp->u_lrval);
2471 break;
2472#endif
2473 default:
2474 fprintf(stderr,
2475 "invalid rval format\n");
2476 break;
2477 }
2478 }
2479 if ((sys_res & RVAL_STR) && tcp->auxstr)
2480 tprintf(" (%s)", tcp->auxstr);
2481 }
2482 if (dtime) {
2483 tv_sub(&tv, &tv, &tcp->etime);
2484 tprintf(" <%ld.%06ld>",
2485 (long) tv.tv_sec, (long) tv.tv_usec);
2486 }
2487 printtrailer();
2488
2489 dumpio(tcp);
2490 if (fflush(tcp->outf) == EOF)
2491 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002492 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002493 tcp->flags &= ~TCB_INSYSCALL;
2494 return 0;
2495}
2496
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002497int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002498trace_syscall(struct tcb *tcp)
2499{
2500 return exiting(tcp) ?
2501 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2502}