blob: b21ce01925f22145fcdc0a1bd1727d10d3627997 [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
Roland McGrathe10e62a2004-09-04 04:20:43 +0000276
Roland McGrath9797ceb2002-12-30 10:23:00 +0000277static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278
Roland McGrathe10e62a2004-09-04 04:20:43 +0000279static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000281 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000282 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000283 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 { QUAL_TRACE, "trace", qual_syscall, "system call" },
286 { QUAL_TRACE, "t", qual_syscall, "system call" },
287 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
288 { QUAL_ABBREV, "a", qual_syscall, "system call" },
289 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
290 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
291 { QUAL_RAW, "raw", qual_syscall, "system call" },
292 { QUAL_RAW, "x", qual_syscall, "system call" },
293 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
294 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
295 { QUAL_SIGNAL, "s", qual_signal, "signal" },
296 { QUAL_FAULT, "fault", qual_fault, "fault" },
297 { QUAL_FAULT, "faults", qual_fault, "fault" },
298 { QUAL_FAULT, "m", qual_fault, "fault" },
299 { QUAL_READ, "read", qual_desc, "descriptor" },
300 { QUAL_READ, "reads", qual_desc, "descriptor" },
301 { QUAL_READ, "r", qual_desc, "descriptor" },
302 { QUAL_WRITE, "write", qual_desc, "descriptor" },
303 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
304 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 { 0, NULL, NULL, NULL },
306};
307
Roland McGrath9797ceb2002-12-30 10:23:00 +0000308static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000309qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000310{
Roland McGrath138c6a32006-01-12 09:50:49 +0000311 if (pers == 0 || pers < 0) {
312 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000313 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000314 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000315 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000316 }
317
318#if SUPPORTED_PERSONALITIES >= 2
319 if (pers == 1 || pers < 0) {
320 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000323 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000324 }
325#endif /* SUPPORTED_PERSONALITIES >= 2 */
326
327#if SUPPORTED_PERSONALITIES >= 3
328 if (pers == 2 || pers < 0) {
329 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000332 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 }
334#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000335}
336
337static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000338qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000339{
340 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000341 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000342
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000343 if (isdigit((unsigned char)*s)) {
344 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000345 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000347 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000348 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000349 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000350 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000351 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000352 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000354 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000355
356#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000357 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000358 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000359 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000360 rc = 0;
361 }
362#endif /* SUPPORTED_PERSONALITIES >= 2 */
363
364#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000365 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000366 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000367 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 rc = 0;
369 }
370#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000371
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000373}
374
375static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000376qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377{
378 int i;
379 char buf[32];
380
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000381 if (isdigit((unsigned char)*s)) {
382 int signo = atoi(s);
383 if (signo < 0 || signo >= MAX_QUALS)
384 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000385 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000386 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000388 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000389 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 strcpy(buf, s);
391 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000392 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000395 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000396 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000397 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000398 }
Roland McGrath76421df2005-02-02 03:51:18 +0000399 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000400}
401
402static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000403qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000404{
405 return -1;
406}
407
408static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000409qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000410{
Roland McGrath48a035f2006-01-12 09:45:56 +0000411 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000412 int desc = atoi(s);
413 if (desc < 0 || desc >= MAX_QUALS)
414 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000415 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000416 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417 }
418 return -1;
419}
420
421static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000422lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423{
424 if (strcmp(s, "file") == 0)
425 return TRACE_FILE;
426 if (strcmp(s, "ipc") == 0)
427 return TRACE_IPC;
428 if (strcmp(s, "network") == 0)
429 return TRACE_NETWORK;
430 if (strcmp(s, "process") == 0)
431 return TRACE_PROCESS;
432 if (strcmp(s, "signal") == 0)
433 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000434 if (strcmp(s, "desc") == 0)
435 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 return -1;
437}
438
439void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000440qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000442 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000444 char *copy;
445 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 int i, n;
447
448 opt = &qual_options[0];
449 for (i = 0; (p = qual_options[i].option_name); i++) {
450 n = strlen(p);
451 if (strncmp(s, p, n) == 0 && s[n] == '=') {
452 opt = &qual_options[i];
453 s += n + 1;
454 break;
455 }
456 }
457 not = 0;
458 if (*s == '!') {
459 not = 1;
460 s++;
461 }
462 if (strcmp(s, "none") == 0) {
463 not = 1 - not;
464 s = "all";
465 }
466 if (strcmp(s, "all") == 0) {
467 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000468 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 }
470 return;
471 }
472 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000473 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000474 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200475 copy = strdup(s);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200476 if (!copy)
477 die_out_of_memory();
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000478 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000480 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000481 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000482 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000483
484#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000485 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000486 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000487 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000488#endif /* SUPPORTED_PERSONALITIES >= 2 */
489
490#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000491 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000492 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000493 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000494#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000495
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496 continue;
497 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000498 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499 fprintf(stderr, "strace: invalid %s `%s'\n",
500 opt->argument_name, p);
501 exit(1);
502 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000504 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 return;
506}
507
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000508#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000509enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000510#else /* FREEBSD */
511enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
512
513struct subcall {
514 int call;
515 int nsubcalls;
516 int subcalls[5];
517};
518
Roland McGratha4d48532005-06-08 20:45:28 +0000519static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000520 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000521#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000522 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000523#else
524 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
525#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000526 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
527};
528#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000530#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531
Roland McGratha4d48532005-06-08 20:45:28 +0000532static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200533decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000535 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200536 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000537 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000538
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 switch (style) {
540 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000541 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
542 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200544 tcp->u_nargs = n = sysent[tcp->scno].nargs;
545 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000546 tcp->u_arg[i] = tcp->u_arg[i + 1];
547 break;
548 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000549 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
550 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551 tcp->scno = subcall + tcp->u_arg[0];
552 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200553 tcp->u_nargs = n = sysent[tcp->scno].nargs;
554 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000555 if (size == sizeof(int)) {
556 unsigned int arg;
557 if (umove(tcp, addr, &arg) < 0)
558 arg = 0;
559 tcp->u_arg[i] = arg;
560 }
561 else if (size == sizeof(long)) {
562 unsigned long arg;
563 if (umove(tcp, addr, &arg) < 0)
564 arg = 0;
565 tcp->u_arg[i] = arg;
566 }
567 else
568 abort();
569 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571 break;
572 case mask_style:
573 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574 for (i = 0; mask; i++)
575 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000576 if (i >= nsubcalls)
577 return;
578 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200580 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000582 case door_style:
583 /*
584 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000585 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000586 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
588 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000589 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200590 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000591 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000592#ifdef FREEBSD
593 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000594 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000595 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000596 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
598 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
599 for (i = 0; i < tcp->u_nargs; i++)
600 tcp->u_arg[i] = tcp->u_arg[i + 1];
601 }
602 break;
603#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000604 }
605}
606#endif
607
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200608int
609printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000610{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200611 if (entering(tcp)) {
612 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200614 for (i = 0; i < tcp->u_nargs; i++)
615 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
616 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 return 0;
618}
619
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200620long
621getrval2(struct tcb *tcp)
622{
623 long val = -1;
624
625#ifdef LINUX
626#if defined (SPARC) || defined (SPARC64)
627 struct pt_regs regs;
628 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
629 return -1;
630 val = regs.u_regs[U_REG_O1];
631#elif defined(SH)
632 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
633 return -1;
634#elif defined(IA64)
635 if (upeek(tcp, PT_R9, &val) < 0)
636 return -1;
637#endif
638#endif /* LINUX */
639
640#ifdef SUNOS4
641 if (upeek(tcp, uoff(u_rval2), &val) < 0)
642 return -1;
643#endif /* SUNOS4 */
644
645#ifdef SVR4
646#ifdef SPARC
647 val = tcp->status.PR_REG[R_O1];
648#endif /* SPARC */
649#ifdef I386
650 val = tcp->status.PR_REG[EDX];
651#endif /* I386 */
652#ifdef X86_64
653 val = tcp->status.PR_REG[RDX];
654#endif /* X86_64 */
655#ifdef MIPS
656 val = tcp->status.PR_REG[CTX_V1];
657#endif /* MIPS */
658#endif /* SVR4 */
659
660#ifdef FREEBSD
661 struct reg regs;
662 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
663 val = regs.r_edx;
664#endif
665 return val;
666}
667
668#ifdef SUNOS4
669/*
670 * Apparently, indirect system calls have already be converted by ptrace(2),
671 * so if you see "indir" this program has gone astray.
672 */
673int
674sys_indir(struct tcb *tcp)
675{
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200676 int i, nargs;
677 long scno;
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200678
679 if (entering(tcp)) {
680 scno = tcp->u_arg[0];
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200681 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenkofabaa912011-08-25 01:23:10 +0200682 fprintf(stderr, "Bogus syscall: %ld\n", scno);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200683 return 0;
684 }
685 nargs = sysent[scno].nargs;
686 tprintf("%s", sysent[scno].sys_name);
687 for (i = 0; i < nargs; i++)
688 tprintf(", %#lx", tcp->u_arg[i+1]);
689 }
690 return 0;
691}
692#endif /* SUNOS4 */
693
694int
695is_restart_error(struct tcb *tcp)
696{
697#ifdef LINUX
698 if (!syserror(tcp))
699 return 0;
700 switch (tcp->u_error) {
701 case ERESTARTSYS:
702 case ERESTARTNOINTR:
703 case ERESTARTNOHAND:
704 case ERESTART_RESTARTBLOCK:
705 return 1;
706 default:
707 break;
708 }
709#endif /* LINUX */
710 return 0;
711}
712
713struct tcb *tcp_last = NULL;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000714
715#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200716# if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200717static struct pt_regs i386_regs;
718# elif defined(X86_64)
719static struct pt_regs x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200720# elif defined (IA64)
721long r8, r10, psr; /* TODO: make static? */
722long ia32 = 0; /* not static */
723# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200724static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200725# elif defined (M68K)
726static long d0;
727# elif defined(BFIN)
728static long r0;
729# elif defined (ARM)
730static struct pt_regs regs;
731# elif defined (ALPHA)
732static long r0;
733static long a3;
734# elif defined(AVR32)
735static struct pt_regs regs;
736# elif defined (SPARC) || defined (SPARC64)
737static struct pt_regs regs;
738static unsigned long trap;
739# elif defined(LINUX_MIPSN32)
740static long long a3;
741static long long r2;
742# elif defined(MIPS)
743static long a3;
744static long r2;
745# elif defined(S390) || defined(S390X)
746static long gpr2;
747static long pc;
748static long syscall_mode;
749# elif defined(HPPA)
750static long r28;
751# elif defined(SH)
752static long r0;
753# elif defined(SH64)
754static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200755# elif defined(CRISV10) || defined(CRISV32)
756static long r10;
757# elif defined(MICROBLAZE)
758static long r3;
759# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000760#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000761#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200762struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000763#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200765/* Returns:
766 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
767 * 1: ok, continue in trace_syscall().
768 * other: error, trace_syscall() should print error indicator
769 * ("????" etc) and bail out.
770 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200771#ifndef USE_PROCFS
772static
773#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200775get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000780# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000781 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200782 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000783
784 if (syscall_mode != -ENOSYS) {
785 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000786 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000787 */
788 scno = syscall_mode;
789 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000790 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000791 * Old style of "passing" the scno via the SVC instruction.
792 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000793 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200794 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200795 static const int gpr_offset[16] = {
796 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
797 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
798 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
799 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
800 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000801
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000802 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000803 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000804 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000805 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000806 if (errno) {
807 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000809 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000810
811 /*
812 * We have to check if the SVC got executed directly or via an
813 * EXECUTE instruction. In case of EXECUTE it is necessary to do
814 * instruction decoding to derive the system call number.
815 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
816 * so that this doesn't work if a SVC opcode is part of an EXECUTE
817 * opcode. Since there is no way to find out the opcode size this
818 * is the best we can do...
819 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000820 if ((opcode & 0xff00) == 0x0a00) {
821 /* SVC opcode */
822 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000823 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 else {
825 /* SVC got executed by EXECUTE instruction */
826
827 /*
828 * Do instruction decoding of EXECUTE. If you really want to
829 * understand this, read the Principles of Operations.
830 */
831 svc_addr = (void *) (opcode & 0xfff);
832
833 tmp = 0;
834 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000835 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 return -1;
837 svc_addr += tmp;
838
839 tmp = 0;
840 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000841 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000842 return -1;
843 svc_addr += tmp;
844
Denys Vlasenkofb036672009-01-23 16:30:26 +0000845 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000846 if (errno)
847 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000848# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000849 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000850# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000852# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 tmp = 0;
854 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000855 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 return -1;
857
858 scno = (scno | tmp) & 0xff;
859 }
860 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000861# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000862 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200864# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200865 /* TODO: speed up strace by not doing this at every syscall.
866 * We only need to do it after execve.
867 */
868 int currpers;
869 long val;
870 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200871
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200872 /* Check for 64/32 bit mode. */
873 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
874 return -1;
875 /* SF is bit 0 of MSR */
876 if (val < 0)
877 currpers = 0;
878 else
879 currpers = 1;
880 if (currpers != current_personality) {
881 static const char *const names[] = {"64 bit", "32 bit"};
882 set_personality(currpers);
883 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
884 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200885 }
886# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000887# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200888 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000889 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
890 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200891 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000892# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000893 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000894 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000895# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200896 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200898 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000899# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200900 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200901 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
902 return -1;
903 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000904
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200905 /* Check CS register value. On x86-64 linux it is:
906 * 0x33 for long mode (64 bit)
907 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200908 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200909 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200910 case 0x23: currpers = 1; break;
911 case 0x33: currpers = 0; break;
912 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200913 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200914 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200915 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200916 currpers = current_personality;
917 break;
918 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000919# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200920 /* This version analyzes the opcode of a syscall instruction.
921 * (int 0x80 on i386 vs. syscall on x86-64)
922 * It works, but is too complicated.
923 */
924 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000925
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200926 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000927
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200928 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
929 rip -= 2;
930 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000931
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200932 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200933 if (errno)
934 fprintf(stderr, "ptrace_peektext failed: %s\n",
935 strerror(errno));
936 switch (call & 0xffff) {
937 /* x86-64: syscall = 0x0f 0x05 */
938 case 0x050f: currpers = 0; break;
939 /* i386: int 0x80 = 0xcd 0x80 */
940 case 0x80cd: currpers = 1; break;
941 default:
942 currpers = current_personality;
943 fprintf(stderr,
944 "Unknown syscall opcode (0x%04X) while "
945 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200946 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200947 break;
948 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000949# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200950 if (currpers != current_personality) {
951 static const char *const names[] = {"64 bit", "32 bit"};
952 set_personality(currpers);
953 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200954 tcp->pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000955 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000956# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000957# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200958 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000959 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200960 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200961 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200962 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000963 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200964 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000965 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200966 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000967# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200968 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000969 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000970 return -1;
971
972 /*
973 * We only need to grab the syscall number on syscall entry.
974 */
975 if (regs.ARM_ip == 0) {
976 /*
977 * Note: we only deal with only 32-bit CPUs here.
978 */
979 if (regs.ARM_cpsr & 0x20) {
980 /*
981 * Get the Thumb-mode system call number
982 */
983 scno = regs.ARM_r7;
984 } else {
985 /*
986 * Get the ARM-mode system call number
987 */
988 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000989 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000990 if (errno)
991 return -1;
992
Roland McGrathf691bd22006-04-25 07:34:41 +0000993 /* Handle the EABI syscall convention. We do not
994 bother converting structures between the two
995 ABIs, but basic functionality should work even
996 if strace and the traced program have different
997 ABIs. */
998 if (scno == 0xef000000) {
999 scno = regs.ARM_r7;
1000 } else {
1001 if ((scno & 0x0ff00000) != 0x0f900000) {
1002 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1003 scno);
1004 return -1;
1005 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001006
Roland McGrathf691bd22006-04-25 07:34:41 +00001007 /*
1008 * Fixup the syscall number
1009 */
1010 scno &= 0x000fffff;
1011 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001012 }
Roland McGrath56703312008-05-20 01:35:55 +00001013 if (scno & 0x0f0000) {
1014 /*
1015 * Handle ARM specific syscall
1016 */
1017 set_personality(1);
1018 scno &= 0x0000ffff;
1019 } else
1020 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001021
Roland McGrath0f87c492003-06-03 23:29:04 +00001022 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001023 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1024 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001026# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001027 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001029# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001030 unsigned long long regs[38];
1031
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001032 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001033 return -1;
1034 a3 = regs[REG_A3];
1035 r2 = regs[REG_V0];
1036
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001037 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001038 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001039 if (a3 == 0 || a3 == -1) {
1040 if (debug)
1041 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001042 return 0;
1043 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001044 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001045# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001046 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001047 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001048 if (upeek(tcp, REG_V0, &scno) < 0)
1049 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001050
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001051 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001052 if (a3 == 0 || a3 == -1) {
1053 if (debug)
1054 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001055 return 0;
1056 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001057 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001058# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001059 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001061 if (upeek(tcp, REG_R0, &scno) < 0)
1062 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001064 /*
1065 * Do some sanity checks to figure out if it's
1066 * really a syscall entry
1067 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001068 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001069 if (a3 == 0 || a3 == -1) {
1070 if (debug)
1071 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072 return 0;
1073 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001075# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001077 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 return -1;
1079
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001080 /* Disassemble the syscall trap. */
1081 /* Retrieve the syscall trap instruction. */
1082 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001083# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001084 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1085 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001086# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001087 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001088# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001089 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001090 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001091
1092 /* Disassemble the trap to see what personality to use. */
1093 switch (trap) {
1094 case 0x91d02010:
1095 /* Linux/SPARC syscall trap. */
1096 set_personality(0);
1097 break;
1098 case 0x91d0206d:
1099 /* Linux/SPARC64 syscall trap. */
1100 set_personality(2);
1101 break;
1102 case 0x91d02000:
1103 /* SunOS syscall trap. (pers 1) */
1104 fprintf(stderr, "syscall: SunOS no support\n");
1105 return -1;
1106 case 0x91d02008:
1107 /* Solaris 2.x syscall trap. (per 2) */
1108 set_personality(1);
1109 break;
1110 case 0x91d02009:
1111 /* NetBSD/FreeBSD syscall trap. */
1112 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1113 return -1;
1114 case 0x91d02027:
1115 /* Solaris 2.x gettimeofday */
1116 set_personality(1);
1117 break;
1118 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001119# if defined (SPARC64)
1120 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1121# else
1122 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1123# endif
1124 return -1;
1125 }
1126
1127 /* Extract the system call number from the registers. */
1128 if (trap == 0x91d02027)
1129 scno = 156;
1130 else
1131 scno = regs.u_regs[U_REG_G1];
1132 if (scno == 0) {
1133 scno = regs.u_regs[U_REG_O0];
1134 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1135 }
1136# elif defined(HPPA)
1137 if (upeek(tcp, PT_GR20, &scno) < 0)
1138 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001139# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001140 /*
1141 * In the new syscall ABI, the system call number is in R3.
1142 */
1143 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1144 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001145
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001146 if (scno < 0) {
1147 /* Odd as it may seem, a glibc bug has been known to cause
1148 glibc to issue bogus negative syscall numbers. So for
1149 our purposes, make strace print what it *should* have been */
1150 long correct_scno = (scno & 0xff);
1151 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001152 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001153 "Detected glibc bug: bogus system call"
1154 " number = %ld, correcting to %ld\n",
1155 scno,
1156 correct_scno);
1157 scno = correct_scno;
1158 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001159# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001161 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001162 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001163# elif defined(CRISV10) || defined(CRISV32)
1164 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1165 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001166# elif defined(TILE)
1167 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1168 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001169# elif defined(MICROBLAZE)
1170 if (upeek(tcp, 0, &scno) < 0)
1171 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001172# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001176 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001178#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001179 /* new syscall ABI returns result in R0 */
1180 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1181 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001182#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001183 /* ABI defines result returned in r9 */
1184 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1185 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001188#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001190 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001191# else
1192# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001193 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001195 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 perror("pread");
1197 return -1;
1198 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001199 switch (regs.r_eax) {
1200 case SYS_syscall:
1201 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001202 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1203 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001204 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001205 scno = regs.r_eax;
1206 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001207 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001208# endif /* FREEBSD */
1209# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001211
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001212 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001213 return 1;
1214}
1215
Roland McGrath17352792005-06-07 23:21:26 +00001216long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001217known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001218{
1219 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001220#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001221 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001222 scno = sysent[scno].native_scno;
1223 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001224#endif
Roland McGrath17352792005-06-07 23:21:26 +00001225 scno += NR_SYSCALL_BASE;
1226 return scno;
1227}
1228
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001229/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001230 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001231 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001232 * 1: ok, continue in trace_syscall().
1233 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001234 * ("????" etc) and bail out.
1235 */
Roland McGratha4d48532005-06-08 20:45:28 +00001236static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001237syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001238{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001239#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001240 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001241
Denys Vlasenkoece98792011-08-25 10:25:35 +02001242 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1243 if (
1244 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001246 || scno == SYS_vfork
1247#endif
John Hughes4e36a812001-04-18 15:11:51 +00001248#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001249 || scno == SYS_fork1
1250#endif
John Hughes4e36a812001-04-18 15:11:51 +00001251#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001252 || scno == SYS_forkall
1253#endif
John Hughes4e36a812001-04-18 15:11:51 +00001254#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001255 || scno == SYS_rfork1
1256#endif
John Hughes4e36a812001-04-18 15:11:51 +00001257#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001258 || scno == SYS_rforkall
1259#endif
1260 ) {
1261 /* We are returning in the child, fake it. */
1262 tcp->status.PR_WHY = PR_SYSENTRY;
1263 trace_syscall(tcp);
1264 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001266 else {
1267 fprintf(stderr, "syscall: missing entry\n");
1268 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 }
1270 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001271#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001272
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001274 if (scno == 0) {
1275 fprintf(stderr, "syscall: missing entry\n");
1276 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001278#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001279
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001281 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001283 if (i386_regs.eax != -ENOSYS) {
1284 if (debug)
1285 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1286 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001288#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001289 {
1290 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001291 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001292 rax = (int)rax; /* sign extend from 32 bits */
1293 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001294 if (debug)
1295 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1296 return 0;
1297 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001298 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001299#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001300 /* TODO: we already fetched PT_GPR2 in get_scno
1301 * and stored it in syscall_mode, reuse it here
1302 * instead of re-fetching?
1303 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001304 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001305 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001306 if (syscall_mode != -ENOSYS)
1307 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001308 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001309 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001310 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001311 return 0;
1312 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001314 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001315 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001317 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001319 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320 return 0;
1321 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001322#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001323 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001324 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001325 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001326 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001327 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001328 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001329 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001330 return 0;
1331 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001333 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001334 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001335 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001336 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001337 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001338 return 0;
1339 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001340#elif defined(MICROBLAZE)
1341 if (upeek(tcp, 3 * 4, &r3) < 0)
1342 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001343 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001344 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001345 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001346 return 0;
1347 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001348#endif
1349#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001350 return 1;
1351}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001353static int
1354internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001355{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001356 /*
1357 * We must always trace a few critical system calls in order to
1358 * correctly support following forks in the presence of tracing
1359 * qualifiers.
1360 */
1361 int (*func)();
1362
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001363 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001364 return 0;
1365
1366 func = sysent[tcp->scno].sys_func;
1367
1368 if ( sys_fork == func
1369#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1370 || sys_vfork == func
1371#endif
1372#ifdef LINUX
1373 || sys_clone == func
1374#endif
1375#if UNIXWARE > 2
1376 || sys_rfork == func
1377#endif
1378 )
1379 return internal_fork(tcp);
1380
1381#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1382 if ( sys_execve == func
1383# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1384 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001385# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001386# if UNIXWARE > 2
1387 || sys_rexecve == func
1388# endif
1389 )
1390 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001391#endif
1392
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001393 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001394}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395
Roland McGratha4d48532005-06-08 20:45:28 +00001396static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001397syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001398{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001400 int i, nargs;
1401
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001402 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001403 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001404 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001405 nargs = tcp->u_nargs = MAX_ARGS;
1406
1407# if defined(S390) || defined(S390X)
1408 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001409 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1410 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001411# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001412 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001413 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1414 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001415# elif defined(IA64)
1416 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001417 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001418 long rbs_end;
1419 /* be backwards compatible with kernel < 2.4.4... */
1420# ifndef PT_RBS_END
1421# define PT_RBS_END PT_AR_BSP
1422# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001423
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001424 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1425 return -1;
1426 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001427 return -1;
1428
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001429 sof = (cfm >> 0) & 0x7f;
1430 sol = (cfm >> 7) & 0x7f;
1431 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1432
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001433 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001434 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1435 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1436 return -1;
1437 }
1438 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001439 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1440 PT_R9 /* ECX = out1 */,
1441 PT_R10 /* EDX = out2 */,
1442 PT_R14 /* ESI = out3 */,
1443 PT_R15 /* EDI = out4 */,
1444 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001445
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001446 for (i = 0; i < nargs; ++i) {
1447 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1448 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001449 /* truncate away IVE sign-extension */
1450 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001451 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001452 }
1453# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1454 /* N32 and N64 both use up to six registers. */
1455 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001456
1457 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1458 return -1;
1459
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001460 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001461 tcp->u_arg[i] = regs[REG_A0 + i];
1462# if defined(LINUX_MIPSN32)
1463 tcp->ext_arg[i] = regs[REG_A0 + i];
1464# endif
1465 }
1466# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001467 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001468 long sp;
1469
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001470 if (upeek(tcp, REG_SP, &sp) < 0)
1471 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001472 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001473 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1474 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001475 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001476 (char *)(tcp->u_arg + 4));
1477 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001478 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001479 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001482# elif defined(POWERPC)
1483# ifndef PT_ORIG_R3
1484# define PT_ORIG_R3 34
1485# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001486 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001487 if (upeek(tcp, (i==0) ?
1488 (sizeof(unsigned long) * PT_ORIG_R3) :
1489 ((i+PT_R3) * sizeof(unsigned long)),
1490 &tcp->u_arg[i]) < 0)
1491 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001493# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001494 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001495 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1496# elif defined(HPPA)
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, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1499 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001500# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001501 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001502 tcp->u_arg[i] = regs.uregs[i];
1503# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001504 (void)i;
1505 (void)nargs;
1506 tcp->u_arg[0] = regs.r12;
1507 tcp->u_arg[1] = regs.r11;
1508 tcp->u_arg[2] = regs.r10;
1509 tcp->u_arg[3] = regs.r9;
1510 tcp->u_arg[4] = regs.r5;
1511 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001512# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001513 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 +02001514
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001515 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001516 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1517 return -1;
1518# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001519 static const int syscall_regs[MAX_ARGS] = {
1520 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1521 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001522 };
1523
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001524 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001525 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001526 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001527# elif defined(SH64)
1528 int i;
1529 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001530 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001531
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001532 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001533 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1534 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001535# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001536 (void)i;
1537 (void)nargs;
1538 if (current_personality == 0) { /* x86-64 ABI */
1539 tcp->u_arg[0] = x86_64_regs.rdi;
1540 tcp->u_arg[1] = x86_64_regs.rsi;
1541 tcp->u_arg[2] = x86_64_regs.rdx;
1542 tcp->u_arg[3] = x86_64_regs.r10;
1543 tcp->u_arg[4] = x86_64_regs.r8;
1544 tcp->u_arg[5] = x86_64_regs.r9;
1545 } else { /* i386 ABI */
1546 /* Sign-extend lower 32 bits */
1547 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1548 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1549 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1550 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1551 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1552 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1553 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001554# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001555 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001556 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1557 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001558# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001559 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001560 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001561 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001562 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001563
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001564 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001565 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1566 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001567# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001568 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001569 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1570 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001571# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001572 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001573 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1574 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001575# elif defined(I386)
1576 (void)i;
1577 (void)nargs;
1578 tcp->u_arg[0] = i386_regs.ebx;
1579 tcp->u_arg[1] = i386_regs.ecx;
1580 tcp->u_arg[2] = i386_regs.edx;
1581 tcp->u_arg[3] = i386_regs.esi;
1582 tcp->u_arg[4] = i386_regs.edi;
1583 tcp->u_arg[5] = i386_regs.ebp;
1584# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001585 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001586 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1587 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001588# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589#endif /* LINUX */
1590#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001591 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001592 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001593 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001594 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001595 nargs = tcp->u_nargs = MAX_ARGS;
1596 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001597 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001599 if (upeek(tcp, uoff(u_arg[0]) +
1600 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1601 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 }
1603#endif /* SUNOS4 */
1604#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001605# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 /*
1607 * SGI is broken: even though it has pr_sysarg, it doesn't
1608 * set them on system call entry. Get a clue.
1609 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001610 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611 tcp->u_nargs = sysent[tcp->scno].nargs;
1612 else
1613 tcp->u_nargs = tcp->status.pr_nsysarg;
1614 if (tcp->u_nargs > 4) {
1615 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001616 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001618 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 }
1620 else {
1621 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001622 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001624# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001625 /*
1626 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1627 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001628 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001629 tcp->u_nargs = sysent[tcp->scno].nargs;
1630 else
1631 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1632 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001633 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1634# elif defined(HAVE_PR_SYSCALL)
1635 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001636 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 tcp->u_nargs = sysent[tcp->scno].nargs;
1638 else
1639 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001640 for (i = 0; i < tcp->u_nargs; i++)
1641 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1642# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001643 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 tcp->u_nargs = sysent[tcp->scno].nargs;
1645 else
1646 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001647 if (tcp->u_nargs > 0)
1648 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001649 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1650# else
John Hughes25299712001-03-06 10:10:06 +00001651 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001652# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001654#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001655 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001656 sysent[tcp->scno].nargs > tcp->status.val)
1657 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001658 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001659 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001660 if (tcp->u_nargs < 0)
1661 tcp->u_nargs = 0;
1662 if (tcp->u_nargs > MAX_ARGS)
1663 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001664 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001665 case SYS___syscall:
1666 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1667 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001668 break;
1669 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001670 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1671 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001672 break;
1673 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001674 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1675 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001676 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001677 }
1678#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001679 return 1;
1680}
1681
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001682static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001683trace_syscall_entering(struct tcb *tcp)
1684{
1685 int res, scno_good;
1686
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001687#if defined TCB_WAITEXECVE
1688 if (tcp->flags & TCB_WAITEXECVE) {
1689 /* This is the post-execve SIGTRAP. */
1690 tcp->flags &= ~TCB_WAITEXECVE;
1691 return 0;
1692 }
1693#endif
1694
Denys Vlasenko06602d92011-08-24 17:53:52 +02001695 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001696 if (res == 0)
1697 return res;
1698 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001699 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001700 if (res == 0)
1701 return res;
1702 if (res == 1)
1703 res = syscall_enter(tcp);
1704 if (res == 0)
1705 return res;
1706
1707 if (res != 1) {
1708 printleader(tcp);
1709 tcp->flags &= ~TCB_REPRINT;
1710 tcp_last = tcp;
1711 if (scno_good != 1)
1712 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001713 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001714 tprintf("syscall_%lu(", tcp->scno);
1715 else
1716 tprintf("%s(", sysent[tcp->scno].sys_name);
1717 /*
1718 * " <unavailable>" will be added later by the code which
1719 * detects ptrace errors.
1720 */
1721 goto ret;
1722 }
1723
1724 switch (known_scno(tcp)) {
1725#ifdef SYS_socket_subcall
1726 case SYS_socketcall:
1727 decode_subcall(tcp, SYS_socket_subcall,
1728 SYS_socket_nsubcalls, deref_style);
1729 break;
1730#endif
1731#ifdef SYS_ipc_subcall
1732 case SYS_ipc:
1733 decode_subcall(tcp, SYS_ipc_subcall,
1734 SYS_ipc_nsubcalls, shift_style);
1735 break;
1736#endif
1737#ifdef SVR4
1738#ifdef SYS_pgrpsys_subcall
1739 case SYS_pgrpsys:
1740 decode_subcall(tcp, SYS_pgrpsys_subcall,
1741 SYS_pgrpsys_nsubcalls, shift_style);
1742 break;
1743#endif /* SYS_pgrpsys_subcall */
1744#ifdef SYS_sigcall_subcall
1745 case SYS_sigcall:
1746 decode_subcall(tcp, SYS_sigcall_subcall,
1747 SYS_sigcall_nsubcalls, mask_style);
1748 break;
1749#endif /* SYS_sigcall_subcall */
1750 case SYS_msgsys:
1751 decode_subcall(tcp, SYS_msgsys_subcall,
1752 SYS_msgsys_nsubcalls, shift_style);
1753 break;
1754 case SYS_shmsys:
1755 decode_subcall(tcp, SYS_shmsys_subcall,
1756 SYS_shmsys_nsubcalls, shift_style);
1757 break;
1758 case SYS_semsys:
1759 decode_subcall(tcp, SYS_semsys_subcall,
1760 SYS_semsys_nsubcalls, shift_style);
1761 break;
1762 case SYS_sysfs:
1763 decode_subcall(tcp, SYS_sysfs_subcall,
1764 SYS_sysfs_nsubcalls, shift_style);
1765 break;
1766 case SYS_spcall:
1767 decode_subcall(tcp, SYS_spcall_subcall,
1768 SYS_spcall_nsubcalls, shift_style);
1769 break;
1770#ifdef SYS_context_subcall
1771 case SYS_context:
1772 decode_subcall(tcp, SYS_context_subcall,
1773 SYS_context_nsubcalls, shift_style);
1774 break;
1775#endif /* SYS_context_subcall */
1776#ifdef SYS_door_subcall
1777 case SYS_door:
1778 decode_subcall(tcp, SYS_door_subcall,
1779 SYS_door_nsubcalls, door_style);
1780 break;
1781#endif /* SYS_door_subcall */
1782#ifdef SYS_kaio_subcall
1783 case SYS_kaio:
1784 decode_subcall(tcp, SYS_kaio_subcall,
1785 SYS_kaio_nsubcalls, shift_style);
1786 break;
1787#endif
1788#endif /* SVR4 */
1789#ifdef FREEBSD
1790 case SYS_msgsys:
1791 case SYS_shmsys:
1792 case SYS_semsys:
1793 decode_subcall(tcp, 0, 0, table_style);
1794 break;
1795#endif
1796#ifdef SUNOS4
1797 case SYS_semsys:
1798 decode_subcall(tcp, SYS_semsys_subcall,
1799 SYS_semsys_nsubcalls, shift_style);
1800 break;
1801 case SYS_msgsys:
1802 decode_subcall(tcp, SYS_msgsys_subcall,
1803 SYS_msgsys_nsubcalls, shift_style);
1804 break;
1805 case SYS_shmsys:
1806 decode_subcall(tcp, SYS_shmsys_subcall,
1807 SYS_shmsys_nsubcalls, shift_style);
1808 break;
1809#endif
1810 }
1811
1812 internal_syscall(tcp);
1813
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001814 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001815 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1816 (tracing_paths && !pathtrace_match(tcp))) {
1817 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1818 return 0;
1819 }
1820
1821 tcp->flags &= ~TCB_FILTERED;
1822
1823 if (cflag == CFLAG_ONLY_STATS) {
1824 res = 0;
1825 goto ret;
1826 }
1827
1828 printleader(tcp);
1829 tcp->flags &= ~TCB_REPRINT;
1830 tcp_last = tcp;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001831 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001832 tprintf("syscall_%lu(", tcp->scno);
1833 else
1834 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001835 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001836 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1837 sysent[tcp->scno].sys_func != sys_exit))
1838 res = printargs(tcp);
1839 else
1840 res = (*sysent[tcp->scno].sys_func)(tcp);
1841
1842 if (fflush(tcp->outf) == EOF)
1843 return -1;
1844 ret:
1845 tcp->flags |= TCB_INSYSCALL;
1846 /* Measure the entrance time as late as possible to avoid errors. */
1847 if (dtime || cflag)
1848 gettimeofday(&tcp->etime, NULL);
1849 return res;
1850}
1851
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001852/* Returns:
1853 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1854 * 1: ok, continue in trace_syscall().
1855 * other: error, trace_syscall() should print error indicator
1856 * ("????" etc) and bail out.
1857 */
1858static int
1859get_syscall_result(struct tcb *tcp)
1860{
1861#ifdef LINUX
1862# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001863 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1864 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001865# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001866# define SO_MASK 0x10000000
1867 {
1868 long flags;
1869 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1870 return -1;
1871 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1872 return -1;
1873 if (flags & SO_MASK)
1874 result = -result;
1875 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001876# elif defined(AVR32)
1877 /* Read complete register set in one go. */
1878 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1879 return -1;
1880# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001881 if (upeek(tcp, PT_R0, &r0) < 0)
1882 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001883# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001884 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001885 return -1;
1886# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001887 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001888 return -1;
1889# elif defined(IA64)
1890# define IA64_PSR_IS ((long)1 << 34)
1891 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1892 ia32 = (psr & IA64_PSR_IS) != 0;
1893 if (upeek(tcp, PT_R8, &r8) < 0)
1894 return -1;
1895 if (upeek(tcp, PT_R10, &r10) < 0)
1896 return -1;
1897# elif defined (ARM)
1898 /* Read complete register set in one go. */
1899 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1900 return -1;
1901# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001902 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1903 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001904# elif defined (LINUX_MIPSN32)
1905 unsigned long long regs[38];
1906
1907 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1908 return -1;
1909 a3 = regs[REG_A3];
1910 r2 = regs[REG_V0];
1911# elif defined (MIPS)
1912 if (upeek(tcp, REG_A3, &a3) < 0)
1913 return -1;
1914 if (upeek(tcp, REG_V0, &r2) < 0)
1915 return -1;
1916# elif defined (ALPHA)
1917 if (upeek(tcp, REG_A3, &a3) < 0)
1918 return -1;
1919 if (upeek(tcp, REG_R0, &r0) < 0)
1920 return -1;
1921# elif defined (SPARC) || defined (SPARC64)
1922 /* Everything we need is in the current register set. */
1923 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1924 return -1;
1925# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001926 if (upeek(tcp, PT_GR28, &r28) < 0)
1927 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001928# elif defined(SH)
1929# elif defined(SH64)
1930# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001931 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1932 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001933# elif defined(TILE)
1934# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001935 if (upeek(tcp, 3 * 4, &r3) < 0)
1936 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001937# endif
1938#endif /* LINUX */
1939
1940#ifdef SUNOS4
1941#elif defined(SH)
1942 /* new syscall ABI returns result in R0 */
1943 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1944 return -1;
1945#elif defined(SH64)
1946 /* ABI defines result returned in r9 */
1947 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1948 return -1;
1949#endif
1950
1951#ifdef USE_PROCFS
1952# ifndef HAVE_PR_SYSCALL
1953# ifdef FREEBSD
1954 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1955 perror("pread");
1956 return -1;
1957 }
1958# endif /* FREEBSD */
1959# endif /* !HAVE_PR_SYSCALL */
1960#endif /* USE_PROCFS */
1961
1962 return 1;
1963}
1964
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001965/* Called at each syscall exit.
1966 * Returns:
1967 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1968 * 1: ok, continue in trace_syscall().
1969 * other: error, trace_syscall() should print error indicator
1970 * ("????" etc) and bail out.
1971 */
1972static int
1973syscall_fixup_on_sysexit(struct tcb *tcp)
1974{
1975#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001976 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1977 fprintf(stderr, "syscall: missing exit\n");
1978 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001979 }
1980#endif /* USE_PROCFS */
1981
1982#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001983 {
1984 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001985 if (scno != 0) {
1986 if (debug) {
1987 /*
1988 * This happens when a signal handler
1989 * for a signal which interrupted a
1990 * a system call makes another system call.
1991 */
1992 fprintf(stderr, "syscall: missing exit\n");
1993 }
1994 tcp->flags &= ~TCB_INSYSCALL;
1995 }
1996 }
1997#endif /* SUNOS4 */
1998
1999#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002000# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002001 if (syscall_mode != -ENOSYS)
2002 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002003 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002004 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2005 /*
2006 * Return from execve.
2007 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2008 * flag set for the post-execve SIGTRAP to see and reset.
2009 */
2010 gpr2 = 0;
2011 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002012# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002013#endif /* LINUX */
2014 return 1;
2015}
2016
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002017#ifdef LINUX
2018/*
2019 * Check the syscall return value register value for whether it is
2020 * a negated errno code indicating an error, or a success return value.
2021 */
2022static inline int
2023is_negated_errno(unsigned long int val)
2024{
2025 unsigned long int max = -(long int) nerrnos;
2026# if SUPPORTED_PERSONALITIES > 1
2027 if (personality_wordsize[current_personality] < sizeof(val)) {
2028 val = (unsigned int) val;
2029 max = (unsigned int) max;
2030 }
2031# endif
2032 return val > max;
2033}
2034#endif
2035
2036static int
2037get_error(struct tcb *tcp)
2038{
2039 int u_error = 0;
2040#ifdef LINUX
2041 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002042 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002043 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2044 check_errno = 0;
2045 }
2046# if defined(S390) || defined(S390X)
2047 if (check_errno && is_negated_errno(gpr2)) {
2048 tcp->u_rval = -1;
2049 u_error = -gpr2;
2050 }
2051 else {
2052 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002053 }
2054# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002055 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002056 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002057 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002058 }
2059 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002060 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002061 }
2062# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002063 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002064 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002065 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002066 }
2067 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002068 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002069 }
2070# elif defined(IA64)
2071 if (ia32) {
2072 int err;
2073
2074 err = (int)r8;
2075 if (check_errno && is_negated_errno(err)) {
2076 tcp->u_rval = -1;
2077 u_error = -err;
2078 }
2079 else {
2080 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002081 }
2082 } else {
2083 if (check_errno && r10) {
2084 tcp->u_rval = -1;
2085 u_error = r8;
2086 } else {
2087 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002088 }
2089 }
2090# elif defined(MIPS)
2091 if (check_errno && a3) {
2092 tcp->u_rval = -1;
2093 u_error = r2;
2094 } else {
2095 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002096 }
2097# elif defined(POWERPC)
2098 if (check_errno && is_negated_errno(result)) {
2099 tcp->u_rval = -1;
2100 u_error = -result;
2101 }
2102 else {
2103 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002104 }
2105# elif defined(M68K)
2106 if (check_errno && is_negated_errno(d0)) {
2107 tcp->u_rval = -1;
2108 u_error = -d0;
2109 }
2110 else {
2111 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002112 }
2113# elif defined(ARM)
2114 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2115 tcp->u_rval = -1;
2116 u_error = -regs.ARM_r0;
2117 }
2118 else {
2119 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002120 }
2121# elif defined(AVR32)
2122 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2123 tcp->u_rval = -1;
2124 u_error = -regs.r12;
2125 }
2126 else {
2127 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002128 }
2129# elif defined(BFIN)
2130 if (check_errno && is_negated_errno(r0)) {
2131 tcp->u_rval = -1;
2132 u_error = -r0;
2133 } else {
2134 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002135 }
2136# elif defined(ALPHA)
2137 if (check_errno && a3) {
2138 tcp->u_rval = -1;
2139 u_error = r0;
2140 }
2141 else {
2142 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002143 }
2144# elif defined(SPARC)
2145 if (check_errno && regs.psr & PSR_C) {
2146 tcp->u_rval = -1;
2147 u_error = regs.u_regs[U_REG_O0];
2148 }
2149 else {
2150 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002151 }
2152# elif defined(SPARC64)
2153 if (check_errno && regs.tstate & 0x1100000000UL) {
2154 tcp->u_rval = -1;
2155 u_error = regs.u_regs[U_REG_O0];
2156 }
2157 else {
2158 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002159 }
2160# elif defined(HPPA)
2161 if (check_errno && is_negated_errno(r28)) {
2162 tcp->u_rval = -1;
2163 u_error = -r28;
2164 }
2165 else {
2166 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002167 }
2168# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002169 if (check_errno && is_negated_errno(r0)) {
2170 tcp->u_rval = -1;
2171 u_error = -r0;
2172 }
2173 else {
2174 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002175 }
2176# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002177 if (check_errno && is_negated_errno(r9)) {
2178 tcp->u_rval = -1;
2179 u_error = -r9;
2180 }
2181 else {
2182 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002183 }
2184# elif defined(CRISV10) || defined(CRISV32)
2185 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2186 tcp->u_rval = -1;
2187 u_error = -r10;
2188 }
2189 else {
2190 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002191 }
2192# elif defined(TILE)
2193 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002194 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2195 return -1;
2196 if (check_errno && rval < 0 && rval > -nerrnos) {
2197 tcp->u_rval = -1;
2198 u_error = -rval;
2199 }
2200 else {
2201 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002202 }
2203# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002204 if (check_errno && is_negated_errno(r3)) {
2205 tcp->u_rval = -1;
2206 u_error = -r3;
2207 }
2208 else {
2209 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002210 }
2211# endif
2212#endif /* LINUX */
2213#ifdef SUNOS4
2214 /* get error code from user struct */
2215 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2216 return -1;
2217 u_error >>= 24; /* u_error is a char */
2218
2219 /* get system call return value */
2220 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2221 return -1;
2222#endif /* SUNOS4 */
2223#ifdef SVR4
2224# ifdef SPARC
2225 /* Judicious guessing goes a long way. */
2226 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2227 tcp->u_rval = -1;
2228 u_error = tcp->status.pr_reg[R_O0];
2229 }
2230 else {
2231 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002232 }
2233# endif /* SPARC */
2234# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002235 if (tcp->status.PR_REG[EFL] & 0x1) {
2236 tcp->u_rval = -1;
2237 u_error = tcp->status.PR_REG[EAX];
2238 }
2239 else {
2240 tcp->u_rval = tcp->status.PR_REG[EAX];
2241# ifdef HAVE_LONG_LONG
2242 tcp->u_lrval =
2243 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2244 tcp->status.PR_REG[EAX];
2245# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002246 }
2247# endif /* I386 */
2248# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002249 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2250 tcp->u_rval = -1;
2251 u_error = tcp->status.PR_REG[RAX];
2252 }
2253 else {
2254 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002255 }
2256# endif /* X86_64 */
2257# ifdef MIPS
2258 if (tcp->status.pr_reg[CTX_A3]) {
2259 tcp->u_rval = -1;
2260 u_error = tcp->status.pr_reg[CTX_V0];
2261 }
2262 else {
2263 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002264 }
2265# endif /* MIPS */
2266#endif /* SVR4 */
2267#ifdef FREEBSD
2268 if (regs.r_eflags & PSL_C) {
2269 tcp->u_rval = -1;
2270 u_error = regs.r_eax;
2271 } else {
2272 tcp->u_rval = regs.r_eax;
2273 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002274 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002275 }
2276#endif /* FREEBSD */
2277 tcp->u_error = u_error;
2278 return 1;
2279}
2280
2281static void
2282dumpio(struct tcb *tcp)
2283{
2284 if (syserror(tcp))
2285 return;
2286 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2287 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002288 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002289 return;
2290 if (sysent[tcp->scno].sys_func == printargs)
2291 return;
2292 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2293 if (sysent[tcp->scno].sys_func == sys_read ||
2294 sysent[tcp->scno].sys_func == sys_pread ||
2295 sysent[tcp->scno].sys_func == sys_pread64 ||
2296 sysent[tcp->scno].sys_func == sys_recv ||
2297 sysent[tcp->scno].sys_func == sys_recvfrom)
2298 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2299 else if (sysent[tcp->scno].sys_func == sys_readv)
2300 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2301 return;
2302 }
2303 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2304 if (sysent[tcp->scno].sys_func == sys_write ||
2305 sysent[tcp->scno].sys_func == sys_pwrite ||
2306 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2307 sysent[tcp->scno].sys_func == sys_send ||
2308 sysent[tcp->scno].sys_func == sys_sendto)
2309 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2310 else if (sysent[tcp->scno].sys_func == sys_writev)
2311 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2312 return;
2313 }
2314}
2315
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002316static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002317trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002318{
2319 int sys_res;
2320 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002321 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002322 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002323
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002324 /* Measure the exit time as early as possible to avoid errors. */
2325 if (dtime || cflag)
2326 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002327
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002328 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002329 if (res == 0)
2330 return res;
2331 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002332 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002333 if (res == 0)
2334 return res;
2335 if (res == 1)
2336 res = get_error(tcp);
2337 if (res == 0)
2338 return res;
2339 if (res == 1)
2340 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002341
Grant Edwards8a082772011-04-07 20:25:40 +00002342 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002343 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002344 }
2345
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002346 if (tcp->flags & TCB_REPRINT) {
2347 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002348 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002349 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002350 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002351 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002352 }
2353
2354 if (cflag) {
2355 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002356 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002357 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002358 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002359 }
2360 }
2361
2362 if (res != 1) {
2363 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002364 tabto();
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002365 tprintf("= ? <unavailable>");
2366 printtrailer();
2367 tcp->flags &= ~TCB_INSYSCALL;
2368 return res;
2369 }
2370
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002371 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002372 || (qual_flags[tcp->scno] & QUAL_RAW))
2373 sys_res = printargs(tcp);
2374 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002375 /* FIXME: not_failing_only (IOW, option -z) is broken:
2376 * failure of syscall is known only after syscall return.
2377 * Thus we end up with something like this on, say, ENOENT:
2378 * open("doesnt_exist", O_RDONLY <unfinished ...>
2379 * {next syscall decode}
2380 * whereas the intended result is that open(...) line
2381 * is not shown at all.
2382 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002383 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002384 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002385 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2386 }
2387
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002388 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002389 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002390 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002391 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002392 qual_flags[tcp->scno] & QUAL_RAW) {
2393 if (u_error)
2394 tprintf("= -1 (errno %ld)", u_error);
2395 else
2396 tprintf("= %#lx", tcp->u_rval);
2397 }
2398 else if (!(sys_res & RVAL_NONE) && u_error) {
2399 switch (u_error) {
2400#ifdef LINUX
2401 case ERESTARTSYS:
2402 tprintf("= ? ERESTARTSYS (To be restarted)");
2403 break;
2404 case ERESTARTNOINTR:
2405 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2406 break;
2407 case ERESTARTNOHAND:
2408 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2409 break;
2410 case ERESTART_RESTARTBLOCK:
2411 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2412 break;
2413#endif /* LINUX */
2414 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002415 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002416 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002417 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002418 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002419 strerror(u_error));
2420 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002421 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002422 strerror(u_error));
2423 break;
2424 }
2425 if ((sys_res & RVAL_STR) && tcp->auxstr)
2426 tprintf(" (%s)", tcp->auxstr);
2427 }
2428 else {
2429 if (sys_res & RVAL_NONE)
2430 tprintf("= ?");
2431 else {
2432 switch (sys_res & RVAL_MASK) {
2433 case RVAL_HEX:
2434 tprintf("= %#lx", tcp->u_rval);
2435 break;
2436 case RVAL_OCTAL:
2437 tprintf("= %#lo", tcp->u_rval);
2438 break;
2439 case RVAL_UDECIMAL:
2440 tprintf("= %lu", tcp->u_rval);
2441 break;
2442 case RVAL_DECIMAL:
2443 tprintf("= %ld", tcp->u_rval);
2444 break;
2445#ifdef HAVE_LONG_LONG
2446 case RVAL_LHEX:
2447 tprintf("= %#llx", tcp->u_lrval);
2448 break;
2449 case RVAL_LOCTAL:
2450 tprintf("= %#llo", tcp->u_lrval);
2451 break;
2452 case RVAL_LUDECIMAL:
2453 tprintf("= %llu", tcp->u_lrval);
2454 break;
2455 case RVAL_LDECIMAL:
2456 tprintf("= %lld", tcp->u_lrval);
2457 break;
2458#endif
2459 default:
2460 fprintf(stderr,
2461 "invalid rval format\n");
2462 break;
2463 }
2464 }
2465 if ((sys_res & RVAL_STR) && tcp->auxstr)
2466 tprintf(" (%s)", tcp->auxstr);
2467 }
2468 if (dtime) {
2469 tv_sub(&tv, &tv, &tcp->etime);
2470 tprintf(" <%ld.%06ld>",
2471 (long) tv.tv_sec, (long) tv.tv_usec);
2472 }
2473 printtrailer();
2474
2475 dumpio(tcp);
2476 if (fflush(tcp->outf) == EOF)
2477 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002478 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002479 tcp->flags &= ~TCB_INSYSCALL;
2480 return 0;
2481}
2482
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002483int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002484trace_syscall(struct tcb *tcp)
2485{
2486 return exiting(tcp) ?
2487 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2488}