blob: 521ca10b1c51366783d1685c7d247013d50ac789 [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);
476 if (!copy) {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000477 fprintf(stderr, "out of memory\n");
478 exit(1);
479 }
480 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000484 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000485
486#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000487 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000488 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000489 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000490#endif /* SUPPORTED_PERSONALITIES >= 2 */
491
492#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000493 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000494 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000495 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000496#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000497
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 continue;
499 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000500 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501 fprintf(stderr, "strace: invalid %s `%s'\n",
502 opt->argument_name, p);
503 exit(1);
504 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000506 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 return;
508}
509
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000510#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000511enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000512#else /* FREEBSD */
513enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
514
515struct subcall {
516 int call;
517 int nsubcalls;
518 int subcalls[5];
519};
520
Roland McGratha4d48532005-06-08 20:45:28 +0000521static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000522 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000523#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000524 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000525#else
526 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
527#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000528 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
529};
530#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000532#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000533
Roland McGratha4d48532005-06-08 20:45:28 +0000534static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200535decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000537 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200538 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000539 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000540
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 switch (style) {
542 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000543 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
544 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000545 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200546 tcp->u_nargs = n = sysent[tcp->scno].nargs;
547 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000548 tcp->u_arg[i] = tcp->u_arg[i + 1];
549 break;
550 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000551 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
552 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553 tcp->scno = subcall + tcp->u_arg[0];
554 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200555 tcp->u_nargs = n = sysent[tcp->scno].nargs;
556 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000557 if (size == sizeof(int)) {
558 unsigned int arg;
559 if (umove(tcp, addr, &arg) < 0)
560 arg = 0;
561 tcp->u_arg[i] = arg;
562 }
563 else if (size == sizeof(long)) {
564 unsigned long arg;
565 if (umove(tcp, addr, &arg) < 0)
566 arg = 0;
567 tcp->u_arg[i] = arg;
568 }
569 else
570 abort();
571 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 break;
574 case mask_style:
575 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 for (i = 0; mask; i++)
577 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000578 if (i >= nsubcalls)
579 return;
580 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200582 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000584 case door_style:
585 /*
586 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000588 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000589 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
590 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000591 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200592 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000593 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000594#ifdef FREEBSD
595 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000596 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000598 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000599 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
600 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
601 for (i = 0; i < tcp->u_nargs; i++)
602 tcp->u_arg[i] = tcp->u_arg[i + 1];
603 }
604 break;
605#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000606 }
607}
608#endif
609
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200610int
611printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200613 if (entering(tcp)) {
614 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200616 for (i = 0; i < tcp->u_nargs; i++)
617 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
618 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 return 0;
620}
621
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200622long
623getrval2(struct tcb *tcp)
624{
625 long val = -1;
626
627#ifdef LINUX
628#if defined (SPARC) || defined (SPARC64)
629 struct pt_regs regs;
630 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
631 return -1;
632 val = regs.u_regs[U_REG_O1];
633#elif defined(SH)
634 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
635 return -1;
636#elif defined(IA64)
637 if (upeek(tcp, PT_R9, &val) < 0)
638 return -1;
639#endif
640#endif /* LINUX */
641
642#ifdef SUNOS4
643 if (upeek(tcp, uoff(u_rval2), &val) < 0)
644 return -1;
645#endif /* SUNOS4 */
646
647#ifdef SVR4
648#ifdef SPARC
649 val = tcp->status.PR_REG[R_O1];
650#endif /* SPARC */
651#ifdef I386
652 val = tcp->status.PR_REG[EDX];
653#endif /* I386 */
654#ifdef X86_64
655 val = tcp->status.PR_REG[RDX];
656#endif /* X86_64 */
657#ifdef MIPS
658 val = tcp->status.PR_REG[CTX_V1];
659#endif /* MIPS */
660#endif /* SVR4 */
661
662#ifdef FREEBSD
663 struct reg regs;
664 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
665 val = regs.r_edx;
666#endif
667 return val;
668}
669
670#ifdef SUNOS4
671/*
672 * Apparently, indirect system calls have already be converted by ptrace(2),
673 * so if you see "indir" this program has gone astray.
674 */
675int
676sys_indir(struct tcb *tcp)
677{
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200678 int i, nargs;
679 long scno;
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200680
681 if (entering(tcp)) {
682 scno = tcp->u_arg[0];
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200683 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenkofabaa912011-08-25 01:23:10 +0200684 fprintf(stderr, "Bogus syscall: %ld\n", scno);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200685 return 0;
686 }
687 nargs = sysent[scno].nargs;
688 tprintf("%s", sysent[scno].sys_name);
689 for (i = 0; i < nargs; i++)
690 tprintf(", %#lx", tcp->u_arg[i+1]);
691 }
692 return 0;
693}
694#endif /* SUNOS4 */
695
696int
697is_restart_error(struct tcb *tcp)
698{
699#ifdef LINUX
700 if (!syserror(tcp))
701 return 0;
702 switch (tcp->u_error) {
703 case ERESTARTSYS:
704 case ERESTARTNOINTR:
705 case ERESTARTNOHAND:
706 case ERESTART_RESTARTBLOCK:
707 return 1;
708 default:
709 break;
710 }
711#endif /* LINUX */
712 return 0;
713}
714
715struct tcb *tcp_last = NULL;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000716
717#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200718# if defined (I386)
719static long eax;
720# elif defined (IA64)
721long r8, r10, psr; /* TODO: make static? */
722long ia32 = 0; /* not static */
723# elif defined (POWERPC)
724static long result, flags;
725# 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;
755# elif defined(X86_64)
756static long rax;
757# elif defined(CRISV10) || defined(CRISV32)
758static long r10;
759# elif defined(MICROBLAZE)
760static long r3;
761# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000762#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000763#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200764struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000765#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000766
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200767/* Returns:
768 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
769 * 1: ok, continue in trace_syscall().
770 * other: error, trace_syscall() should print error indicator
771 * ("????" etc) and bail out.
772 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200773#ifndef USE_PROCFS
774static
775#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200777get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000782# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000783 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200784 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000785
786 if (syscall_mode != -ENOSYS) {
787 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000788 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000789 */
790 scno = syscall_mode;
791 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000792 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000793 * Old style of "passing" the scno via the SVC instruction.
794 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000795 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200796 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200797 static const int gpr_offset[16] = {
798 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
799 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
800 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
801 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
802 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000803
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000804 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000805 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000806 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000807 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000808 if (errno) {
809 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000810 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000811 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000812
813 /*
814 * We have to check if the SVC got executed directly or via an
815 * EXECUTE instruction. In case of EXECUTE it is necessary to do
816 * instruction decoding to derive the system call number.
817 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
818 * so that this doesn't work if a SVC opcode is part of an EXECUTE
819 * opcode. Since there is no way to find out the opcode size this
820 * is the best we can do...
821 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 if ((opcode & 0xff00) == 0x0a00) {
823 /* SVC opcode */
824 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000825 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000826 else {
827 /* SVC got executed by EXECUTE instruction */
828
829 /*
830 * Do instruction decoding of EXECUTE. If you really want to
831 * understand this, read the Principles of Operations.
832 */
833 svc_addr = (void *) (opcode & 0xfff);
834
835 tmp = 0;
836 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000837 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
839 svc_addr += tmp;
840
841 tmp = 0;
842 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000843 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000844 return -1;
845 svc_addr += tmp;
846
Denys Vlasenkofb036672009-01-23 16:30:26 +0000847 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000848 if (errno)
849 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000850# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000852# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000854# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000855 tmp = 0;
856 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000857 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000858 return -1;
859
860 scno = (scno | tmp) & 0xff;
861 }
862 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000863# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000864 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200866# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200867 /* TODO: speed up strace by not doing this at every syscall.
868 * We only need to do it after execve.
869 */
870 int currpers;
871 long val;
872 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200873
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200874 /* Check for 64/32 bit mode. */
875 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
876 return -1;
877 /* SF is bit 0 of MSR */
878 if (val < 0)
879 currpers = 0;
880 else
881 currpers = 1;
882 if (currpers != current_personality) {
883 static const char *const names[] = {"64 bit", "32 bit"};
884 set_personality(currpers);
885 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
886 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200887 }
888# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000889# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200890 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000891 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
892 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200893 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000894# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000895 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000896 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000897# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000898 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000900# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000901 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000902 return -1;
903
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200904 /* TODO: speed up strace by not doing this at every syscall.
905 * We only need to do it after execve.
906 */
907 int currpers;
908 long val;
909 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000910
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200911 /* Check CS register value. On x86-64 linux it is:
912 * 0x33 for long mode (64 bit)
913 * 0x23 for compatibility mode (32 bit)
914 * It takes only one ptrace and thus doesn't need
915 * to be cached.
916 */
917 if (upeek(tcp, 8*CS, &val) < 0)
918 return -1;
919 switch (val) {
920 case 0x23: currpers = 1; break;
921 case 0x33: currpers = 0; break;
922 default:
923 fprintf(stderr, "Unknown value CS=0x%02X while "
924 "detecting personality of process "
925 "PID=%d\n", (int)val, pid);
926 currpers = current_personality;
927 break;
928 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000929# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 /* This version analyzes the opcode of a syscall instruction.
931 * (int 0x80 on i386 vs. syscall on x86-64)
932 * It works, but is too complicated.
933 */
934 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000935
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200936 if (upeek(tcp, 8*RIP, &rip) < 0)
937 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000938
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200939 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
940 rip -= 2;
941 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000942
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200943 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
944 if (errno)
945 fprintf(stderr, "ptrace_peektext failed: %s\n",
946 strerror(errno));
947 switch (call & 0xffff) {
948 /* x86-64: syscall = 0x0f 0x05 */
949 case 0x050f: currpers = 0; break;
950 /* i386: int 0x80 = 0xcd 0x80 */
951 case 0x80cd: currpers = 1; break;
952 default:
953 currpers = current_personality;
954 fprintf(stderr,
955 "Unknown syscall opcode (0x%04X) while "
956 "detecting personality of process "
957 "PID=%d\n", (int)call, pid);
958 break;
959 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000960# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200961 if (currpers != current_personality) {
962 static const char *const names[] = {"64 bit", "32 bit"};
963 set_personality(currpers);
964 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
965 pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000966 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000967# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000968# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200969 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000970 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200971 if (ia32) {
972 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
973 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000974 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200975 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000976 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200977 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000978# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200979 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000980 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000981 return -1;
982
983 /*
984 * We only need to grab the syscall number on syscall entry.
985 */
986 if (regs.ARM_ip == 0) {
987 /*
988 * Note: we only deal with only 32-bit CPUs here.
989 */
990 if (regs.ARM_cpsr & 0x20) {
991 /*
992 * Get the Thumb-mode system call number
993 */
994 scno = regs.ARM_r7;
995 } else {
996 /*
997 * Get the ARM-mode system call number
998 */
999 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001000 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001001 if (errno)
1002 return -1;
1003
Roland McGrathf691bd22006-04-25 07:34:41 +00001004 /* Handle the EABI syscall convention. We do not
1005 bother converting structures between the two
1006 ABIs, but basic functionality should work even
1007 if strace and the traced program have different
1008 ABIs. */
1009 if (scno == 0xef000000) {
1010 scno = regs.ARM_r7;
1011 } else {
1012 if ((scno & 0x0ff00000) != 0x0f900000) {
1013 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1014 scno);
1015 return -1;
1016 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001017
Roland McGrathf691bd22006-04-25 07:34:41 +00001018 /*
1019 * Fixup the syscall number
1020 */
1021 scno &= 0x000fffff;
1022 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 }
Roland McGrath56703312008-05-20 01:35:55 +00001024 if (scno & 0x0f0000) {
1025 /*
1026 * Handle ARM specific syscall
1027 */
1028 set_personality(1);
1029 scno &= 0x0000ffff;
1030 } else
1031 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001032
Roland McGrath0f87c492003-06-03 23:29:04 +00001033 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001034 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1035 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001037# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001038 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001040# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001041 unsigned long long regs[38];
1042
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001043 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001044 return -1;
1045 a3 = regs[REG_A3];
1046 r2 = regs[REG_V0];
1047
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001048 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001049 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001050 if (a3 == 0 || a3 == -1) {
1051 if (debug)
1052 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001053 return 0;
1054 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001055 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001056# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001057 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001058 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001059 if (upeek(tcp, REG_V0, &scno) < 0)
1060 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001061
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001062 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 if (a3 == 0 || a3 == -1) {
1064 if (debug)
1065 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001066 return 0;
1067 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001068 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001069# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001070 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001072 if (upeek(tcp, REG_R0, &scno) < 0)
1073 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001075 /*
1076 * Do some sanity checks to figure out if it's
1077 * really a syscall entry
1078 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001079 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001080 if (a3 == 0 || a3 == -1) {
1081 if (debug)
1082 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return 0;
1084 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001086# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001088 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 return -1;
1090
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001091 /* Disassemble the syscall trap. */
1092 /* Retrieve the syscall trap instruction. */
1093 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001094# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001095 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1096 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001097# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001098 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001099# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001100 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001101 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001102
1103 /* Disassemble the trap to see what personality to use. */
1104 switch (trap) {
1105 case 0x91d02010:
1106 /* Linux/SPARC syscall trap. */
1107 set_personality(0);
1108 break;
1109 case 0x91d0206d:
1110 /* Linux/SPARC64 syscall trap. */
1111 set_personality(2);
1112 break;
1113 case 0x91d02000:
1114 /* SunOS syscall trap. (pers 1) */
1115 fprintf(stderr, "syscall: SunOS no support\n");
1116 return -1;
1117 case 0x91d02008:
1118 /* Solaris 2.x syscall trap. (per 2) */
1119 set_personality(1);
1120 break;
1121 case 0x91d02009:
1122 /* NetBSD/FreeBSD syscall trap. */
1123 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1124 return -1;
1125 case 0x91d02027:
1126 /* Solaris 2.x gettimeofday */
1127 set_personality(1);
1128 break;
1129 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001130# if defined (SPARC64)
1131 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1132# else
1133 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1134# endif
1135 return -1;
1136 }
1137
1138 /* Extract the system call number from the registers. */
1139 if (trap == 0x91d02027)
1140 scno = 156;
1141 else
1142 scno = regs.u_regs[U_REG_G1];
1143 if (scno == 0) {
1144 scno = regs.u_regs[U_REG_O0];
1145 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1146 }
1147# elif defined(HPPA)
1148 if (upeek(tcp, PT_GR20, &scno) < 0)
1149 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001150# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001151 /*
1152 * In the new syscall ABI, the system call number is in R3.
1153 */
1154 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1155 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001156
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001157 if (scno < 0) {
1158 /* Odd as it may seem, a glibc bug has been known to cause
1159 glibc to issue bogus negative syscall numbers. So for
1160 our purposes, make strace print what it *should* have been */
1161 long correct_scno = (scno & 0xff);
1162 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001163 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001164 "Detected glibc bug: bogus system call"
1165 " number = %ld, correcting to %ld\n",
1166 scno,
1167 correct_scno);
1168 scno = correct_scno;
1169 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001170# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001171 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001172 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001173 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# elif defined(CRISV10) || defined(CRISV32)
1175 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1176 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001177# elif defined(TILE)
1178 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1179 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001180# elif defined(MICROBLAZE)
1181 if (upeek(tcp, 0, &scno) < 0)
1182 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001183# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001185
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001187 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001189#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001190 /* new syscall ABI returns result in R0 */
1191 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1192 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001193#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001194 /* ABI defines result returned in r9 */
1195 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1196 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001198
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001199#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001200# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001201 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202# else
1203# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001204 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001205# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001206 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001207 perror("pread");
1208 return -1;
1209 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210 switch (regs.r_eax) {
1211 case SYS_syscall:
1212 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1214 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001215 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001216 scno = regs.r_eax;
1217 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001218 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001219# endif /* FREEBSD */
1220# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001221#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001222
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001223 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001224 return 1;
1225}
1226
Roland McGrath17352792005-06-07 23:21:26 +00001227long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001228known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001229{
1230 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001231#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001232 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001233 scno = sysent[scno].native_scno;
1234 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001235#endif
Roland McGrath17352792005-06-07 23:21:26 +00001236 scno += NR_SYSCALL_BASE;
1237 return scno;
1238}
1239
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001240/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001241 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001242 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001243 * 1: ok, continue in trace_syscall().
1244 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001245 * ("????" etc) and bail out.
1246 */
Roland McGratha4d48532005-06-08 20:45:28 +00001247static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001249{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001251 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001252
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001253 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001254 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 if (
1256 scno == SYS_fork
1257#ifdef SYS_vfork
1258 || scno == SYS_vfork
1259#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001260#ifdef SYS_fork1
1261 || scno == SYS_fork1
1262#endif /* SYS_fork1 */
1263#ifdef SYS_forkall
1264 || scno == SYS_forkall
1265#endif /* SYS_forkall */
1266#ifdef SYS_rfork1
1267 || scno == SYS_rfork1
1268#endif /* SYS_fork1 */
1269#ifdef SYS_rforkall
1270 || scno == SYS_rforkall
1271#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001272 ) {
1273 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001274 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001276 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277 }
1278 else {
1279 fprintf(stderr, "syscall: missing entry\n");
1280 tcp->flags |= TCB_INSYSCALL;
1281 }
1282 }
1283 }
1284 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001285 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 fprintf(stderr, "syscall: missing exit\n");
1287 tcp->flags &= ~TCB_INSYSCALL;
1288 }
1289 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001290#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001291
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001293 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294 if (scno == 0) {
1295 fprintf(stderr, "syscall: missing entry\n");
1296 tcp->flags |= TCB_INSYSCALL;
1297 }
1298 }
1299 else {
1300 if (scno != 0) {
1301 if (debug) {
1302 /*
1303 * This happens when a signal handler
1304 * for a signal which interrupted a
1305 * a system call makes another system call.
1306 */
1307 fprintf(stderr, "syscall: missing exit\n");
1308 }
1309 tcp->flags &= ~TCB_INSYSCALL;
1310 }
1311 }
1312#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001313
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001315 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#if defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001317 /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
1318 * Every extra ptrace call is expensive, so check EAX
1319 * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
1320 */
1321 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1322 if (upeek(tcp, 4*EAX, &eax) < 0)
1323 return -1;
1324 if (eax != -ENOSYS) {
1325 if (debug)
1326 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
1327 return 0;
1328 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001330#elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001331 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1332 if (upeek(tcp, 8*RAX, &rax) < 0)
1333 return -1;
1334 if (current_personality == 1)
1335 rax = (long int)(int)rax; /* sign extend from 32 bits */
1336 if (rax != -ENOSYS && entering(tcp)) {
1337 if (debug)
1338 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1339 return 0;
1340 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001341 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001342#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001343 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001344 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001345 if (syscall_mode != -ENOSYS)
1346 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001347 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001348 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001349 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001350 return 0;
1351 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001352 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1353 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1354 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1355 /*
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001356 * Return from execve.
Roland McGrath96dc5142003-01-20 10:23:04 +00001357 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1358 * flag set for the post-execve SIGTRAP to see and reset.
1359 */
1360 gpr2 = 0;
1361 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362#elif defined (POWERPC)
1363# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001364 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001366 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 return -1;
1368 if (flags & SO_MASK)
1369 result = -result;
1370#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001371 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001372 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001373 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001375 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 return 0;
1377 }
1378#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001379 /*
1380 * Nothing required
1381 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001382#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001383 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001384 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001385#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001386 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001387 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001388#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001389 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001390 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001391 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001392 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001393 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001394 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001395 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001396 return 0;
1397 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001398#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001399 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001400 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001401 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001402 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001403 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001404 return 0;
1405 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001406#elif defined(MICROBLAZE)
1407 if (upeek(tcp, 3 * 4, &r3) < 0)
1408 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001409 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001410 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001411 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001412 return 0;
1413 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414#endif
1415#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001416 return 1;
1417}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001418
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001419static int
1420internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001421{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001422 /*
1423 * We must always trace a few critical system calls in order to
1424 * correctly support following forks in the presence of tracing
1425 * qualifiers.
1426 */
1427 int (*func)();
1428
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001429 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001430 return 0;
1431
1432 func = sysent[tcp->scno].sys_func;
1433
1434 if ( sys_fork == func
1435#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1436 || sys_vfork == func
1437#endif
1438#ifdef LINUX
1439 || sys_clone == func
1440#endif
1441#if UNIXWARE > 2
1442 || sys_rfork == func
1443#endif
1444 )
1445 return internal_fork(tcp);
1446
1447#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1448 if ( sys_execve == func
1449# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1450 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001451# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001452# if UNIXWARE > 2
1453 || sys_rexecve == func
1454# endif
1455 )
1456 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001457#endif
1458
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001459 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001460}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001461
Roland McGratha4d48532005-06-08 20:45:28 +00001462static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001463syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001464{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001465#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001466 int i, nargs;
1467
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001468 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001469 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001470 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001471 nargs = tcp->u_nargs = MAX_ARGS;
1472
1473# if defined(S390) || defined(S390X)
1474 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001475 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1476 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001477# elif defined(ALPHA)
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)
1480 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001481# elif defined(IA64)
1482 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001483 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001484 long rbs_end;
1485 /* be backwards compatible with kernel < 2.4.4... */
1486# ifndef PT_RBS_END
1487# define PT_RBS_END PT_AR_BSP
1488# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001489
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001490 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1491 return -1;
1492 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001493 return -1;
1494
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001495 sof = (cfm >> 0) & 0x7f;
1496 sol = (cfm >> 7) & 0x7f;
1497 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1498
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001499 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001500 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1501 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1502 return -1;
1503 }
1504 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001505 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1506 PT_R9 /* ECX = out1 */,
1507 PT_R10 /* EDX = out2 */,
1508 PT_R14 /* ESI = out3 */,
1509 PT_R15 /* EDI = out4 */,
1510 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001511
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001512 for (i = 0; i < nargs; ++i) {
1513 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1514 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001515 /* truncate away IVE sign-extension */
1516 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001517 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001518 }
1519# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1520 /* N32 and N64 both use up to six registers. */
1521 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001522
1523 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1524 return -1;
1525
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001526 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001527 tcp->u_arg[i] = regs[REG_A0 + i];
1528# if defined(LINUX_MIPSN32)
1529 tcp->ext_arg[i] = regs[REG_A0 + i];
1530# endif
1531 }
1532# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001533 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001534 long sp;
1535
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001536 if (upeek(tcp, REG_SP, &sp) < 0)
1537 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001538 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001539 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1540 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001541 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001542 (char *)(tcp->u_arg + 4));
1543 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001544 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001545 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001548# elif defined(POWERPC)
1549# ifndef PT_ORIG_R3
1550# define PT_ORIG_R3 34
1551# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001552 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001553 if (upeek(tcp, (i==0) ?
1554 (sizeof(unsigned long) * PT_ORIG_R3) :
1555 ((i+PT_R3) * sizeof(unsigned long)),
1556 &tcp->u_arg[i]) < 0)
1557 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001559# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001560 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001561 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1562# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001563 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001564 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1565 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001566# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001567 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001568 tcp->u_arg[i] = regs.uregs[i];
1569# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001570 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
1571 &regs.r11,
1572 &regs.r10,
1573 &regs.r9,
1574 &regs.r5,
1575 &regs.r3 };
1576 for (i = 0; i < nargs; ++i)
1577 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001578# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001579 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 +02001580
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001581 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001582 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1583 return -1;
1584# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001585 static const int syscall_regs[MAX_ARGS] = {
1586 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1587 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001588 };
1589
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001590 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001591 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001592 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001593# elif defined(SH64)
1594 int i;
1595 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001596 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001597
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001598 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001599 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1600 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001601# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001602 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
1603 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
1604 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001605 };
1606
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001607 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001608 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001609 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001610# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001611 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001612 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1613 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001614# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001615 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001616 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001617 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001618 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001619
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001620 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001621 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1622 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001623# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001624 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001625 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1626 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001627# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001628 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001629 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1630 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001631# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001632 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001633 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1634 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001635# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636#endif /* LINUX */
1637#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001638 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001639 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001640 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001641 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001642 nargs = tcp->u_nargs = MAX_ARGS;
1643 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001644 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001646 if (upeek(tcp, uoff(u_arg[0]) +
1647 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1648 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 }
1650#endif /* SUNOS4 */
1651#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001652# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 /*
1654 * SGI is broken: even though it has pr_sysarg, it doesn't
1655 * set them on system call entry. Get a clue.
1656 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001657 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 tcp->u_nargs = sysent[tcp->scno].nargs;
1659 else
1660 tcp->u_nargs = tcp->status.pr_nsysarg;
1661 if (tcp->u_nargs > 4) {
1662 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001663 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001665 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 }
1667 else {
1668 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001669 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001671# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001672 /*
1673 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1674 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001675 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001676 tcp->u_nargs = sysent[tcp->scno].nargs;
1677 else
1678 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1679 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001680 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1681# elif defined(HAVE_PR_SYSCALL)
1682 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001683 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 tcp->u_nargs = sysent[tcp->scno].nargs;
1685 else
1686 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001687 for (i = 0; i < tcp->u_nargs; i++)
1688 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1689# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001690 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691 tcp->u_nargs = sysent[tcp->scno].nargs;
1692 else
1693 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001694 if (tcp->u_nargs > 0)
1695 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001696 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1697# else
John Hughes25299712001-03-06 10:10:06 +00001698 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001699# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001701#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001702 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001703 sysent[tcp->scno].nargs > tcp->status.val)
1704 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001705 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001706 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001707 if (tcp->u_nargs < 0)
1708 tcp->u_nargs = 0;
1709 if (tcp->u_nargs > MAX_ARGS)
1710 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001711 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001712 case SYS___syscall:
1713 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1714 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001715 break;
1716 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001717 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1718 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001719 break;
1720 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001721 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1722 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001723 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001724 }
1725#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001726 return 1;
1727}
1728
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001729static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001730trace_syscall_entering(struct tcb *tcp)
1731{
1732 int res, scno_good;
1733
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001734#if defined TCB_WAITEXECVE
1735 if (tcp->flags & TCB_WAITEXECVE) {
1736 /* This is the post-execve SIGTRAP. */
1737 tcp->flags &= ~TCB_WAITEXECVE;
1738 return 0;
1739 }
1740#endif
1741
Denys Vlasenko06602d92011-08-24 17:53:52 +02001742 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001743 if (res == 0)
1744 return res;
1745 if (res == 1)
1746 res = syscall_fixup(tcp);
1747 if (res == 0)
1748 return res;
1749 if (res == 1)
1750 res = syscall_enter(tcp);
1751 if (res == 0)
1752 return res;
1753
1754 if (res != 1) {
1755 printleader(tcp);
1756 tcp->flags &= ~TCB_REPRINT;
1757 tcp_last = tcp;
1758 if (scno_good != 1)
1759 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001760 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001761 tprintf("syscall_%lu(", tcp->scno);
1762 else
1763 tprintf("%s(", sysent[tcp->scno].sys_name);
1764 /*
1765 * " <unavailable>" will be added later by the code which
1766 * detects ptrace errors.
1767 */
1768 goto ret;
1769 }
1770
1771 switch (known_scno(tcp)) {
1772#ifdef SYS_socket_subcall
1773 case SYS_socketcall:
1774 decode_subcall(tcp, SYS_socket_subcall,
1775 SYS_socket_nsubcalls, deref_style);
1776 break;
1777#endif
1778#ifdef SYS_ipc_subcall
1779 case SYS_ipc:
1780 decode_subcall(tcp, SYS_ipc_subcall,
1781 SYS_ipc_nsubcalls, shift_style);
1782 break;
1783#endif
1784#ifdef SVR4
1785#ifdef SYS_pgrpsys_subcall
1786 case SYS_pgrpsys:
1787 decode_subcall(tcp, SYS_pgrpsys_subcall,
1788 SYS_pgrpsys_nsubcalls, shift_style);
1789 break;
1790#endif /* SYS_pgrpsys_subcall */
1791#ifdef SYS_sigcall_subcall
1792 case SYS_sigcall:
1793 decode_subcall(tcp, SYS_sigcall_subcall,
1794 SYS_sigcall_nsubcalls, mask_style);
1795 break;
1796#endif /* SYS_sigcall_subcall */
1797 case SYS_msgsys:
1798 decode_subcall(tcp, SYS_msgsys_subcall,
1799 SYS_msgsys_nsubcalls, shift_style);
1800 break;
1801 case SYS_shmsys:
1802 decode_subcall(tcp, SYS_shmsys_subcall,
1803 SYS_shmsys_nsubcalls, shift_style);
1804 break;
1805 case SYS_semsys:
1806 decode_subcall(tcp, SYS_semsys_subcall,
1807 SYS_semsys_nsubcalls, shift_style);
1808 break;
1809 case SYS_sysfs:
1810 decode_subcall(tcp, SYS_sysfs_subcall,
1811 SYS_sysfs_nsubcalls, shift_style);
1812 break;
1813 case SYS_spcall:
1814 decode_subcall(tcp, SYS_spcall_subcall,
1815 SYS_spcall_nsubcalls, shift_style);
1816 break;
1817#ifdef SYS_context_subcall
1818 case SYS_context:
1819 decode_subcall(tcp, SYS_context_subcall,
1820 SYS_context_nsubcalls, shift_style);
1821 break;
1822#endif /* SYS_context_subcall */
1823#ifdef SYS_door_subcall
1824 case SYS_door:
1825 decode_subcall(tcp, SYS_door_subcall,
1826 SYS_door_nsubcalls, door_style);
1827 break;
1828#endif /* SYS_door_subcall */
1829#ifdef SYS_kaio_subcall
1830 case SYS_kaio:
1831 decode_subcall(tcp, SYS_kaio_subcall,
1832 SYS_kaio_nsubcalls, shift_style);
1833 break;
1834#endif
1835#endif /* SVR4 */
1836#ifdef FREEBSD
1837 case SYS_msgsys:
1838 case SYS_shmsys:
1839 case SYS_semsys:
1840 decode_subcall(tcp, 0, 0, table_style);
1841 break;
1842#endif
1843#ifdef SUNOS4
1844 case SYS_semsys:
1845 decode_subcall(tcp, SYS_semsys_subcall,
1846 SYS_semsys_nsubcalls, shift_style);
1847 break;
1848 case SYS_msgsys:
1849 decode_subcall(tcp, SYS_msgsys_subcall,
1850 SYS_msgsys_nsubcalls, shift_style);
1851 break;
1852 case SYS_shmsys:
1853 decode_subcall(tcp, SYS_shmsys_subcall,
1854 SYS_shmsys_nsubcalls, shift_style);
1855 break;
1856#endif
1857 }
1858
1859 internal_syscall(tcp);
1860
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001861 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001862 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1863 (tracing_paths && !pathtrace_match(tcp))) {
1864 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1865 return 0;
1866 }
1867
1868 tcp->flags &= ~TCB_FILTERED;
1869
1870 if (cflag == CFLAG_ONLY_STATS) {
1871 res = 0;
1872 goto ret;
1873 }
1874
1875 printleader(tcp);
1876 tcp->flags &= ~TCB_REPRINT;
1877 tcp_last = tcp;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001878 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001879 tprintf("syscall_%lu(", tcp->scno);
1880 else
1881 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001882 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001883 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1884 sysent[tcp->scno].sys_func != sys_exit))
1885 res = printargs(tcp);
1886 else
1887 res = (*sysent[tcp->scno].sys_func)(tcp);
1888
1889 if (fflush(tcp->outf) == EOF)
1890 return -1;
1891 ret:
1892 tcp->flags |= TCB_INSYSCALL;
1893 /* Measure the entrance time as late as possible to avoid errors. */
1894 if (dtime || cflag)
1895 gettimeofday(&tcp->etime, NULL);
1896 return res;
1897}
1898
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001899/* Returns:
1900 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1901 * 1: ok, continue in trace_syscall().
1902 * other: error, trace_syscall() should print error indicator
1903 * ("????" etc) and bail out.
1904 */
1905static int
1906get_syscall_result(struct tcb *tcp)
1907{
1908#ifdef LINUX
1909# if defined(S390) || defined(S390X)
1910# elif defined (POWERPC)
1911# elif defined(AVR32)
1912 /* Read complete register set in one go. */
1913 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1914 return -1;
1915# elif defined(BFIN)
1916# elif defined (I386)
1917 if (upeek(tcp, 4*EAX, &eax) < 0)
1918 return -1;
1919# elif defined (X86_64)
1920 if (upeek(tcp, 8*RAX, &rax) < 0)
1921 return -1;
1922# elif defined(IA64)
1923# define IA64_PSR_IS ((long)1 << 34)
1924 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1925 ia32 = (psr & IA64_PSR_IS) != 0;
1926 if (upeek(tcp, PT_R8, &r8) < 0)
1927 return -1;
1928 if (upeek(tcp, PT_R10, &r10) < 0)
1929 return -1;
1930# elif defined (ARM)
1931 /* Read complete register set in one go. */
1932 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1933 return -1;
1934# elif defined (M68K)
1935# elif defined (LINUX_MIPSN32)
1936 unsigned long long regs[38];
1937
1938 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1939 return -1;
1940 a3 = regs[REG_A3];
1941 r2 = regs[REG_V0];
1942# elif defined (MIPS)
1943 if (upeek(tcp, REG_A3, &a3) < 0)
1944 return -1;
1945 if (upeek(tcp, REG_V0, &r2) < 0)
1946 return -1;
1947# elif defined (ALPHA)
1948 if (upeek(tcp, REG_A3, &a3) < 0)
1949 return -1;
1950 if (upeek(tcp, REG_R0, &r0) < 0)
1951 return -1;
1952# elif defined (SPARC) || defined (SPARC64)
1953 /* Everything we need is in the current register set. */
1954 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1955 return -1;
1956# elif defined(HPPA)
1957# elif defined(SH)
1958# elif defined(SH64)
1959# elif defined(CRISV10) || defined(CRISV32)
1960# elif defined(TILE)
1961# elif defined(MICROBLAZE)
1962# endif
1963#endif /* LINUX */
1964
1965#ifdef SUNOS4
1966#elif defined(SH)
1967 /* new syscall ABI returns result in R0 */
1968 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1969 return -1;
1970#elif defined(SH64)
1971 /* ABI defines result returned in r9 */
1972 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1973 return -1;
1974#endif
1975
1976#ifdef USE_PROCFS
1977# ifndef HAVE_PR_SYSCALL
1978# ifdef FREEBSD
1979 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1980 perror("pread");
1981 return -1;
1982 }
1983# endif /* FREEBSD */
1984# endif /* !HAVE_PR_SYSCALL */
1985#endif /* USE_PROCFS */
1986
1987 return 1;
1988}
1989
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001990/* Called at each syscall exit.
1991 * Returns:
1992 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1993 * 1: ok, continue in trace_syscall().
1994 * other: error, trace_syscall() should print error indicator
1995 * ("????" etc) and bail out.
1996 */
1997static int
1998syscall_fixup_on_sysexit(struct tcb *tcp)
1999{
2000#ifdef USE_PROCFS
2001 int scno = known_scno(tcp);
2002
2003 if (entering(tcp)) {
2004 if (tcp->status.PR_WHY != PR_SYSENTRY) {
2005 if (
2006 scno == SYS_fork
2007#ifdef SYS_vfork
2008 || scno == SYS_vfork
2009#endif /* SYS_vfork */
2010#ifdef SYS_fork1
2011 || scno == SYS_fork1
2012#endif /* SYS_fork1 */
2013#ifdef SYS_forkall
2014 || scno == SYS_forkall
2015#endif /* SYS_forkall */
2016#ifdef SYS_rfork1
2017 || scno == SYS_rfork1
2018#endif /* SYS_fork1 */
2019#ifdef SYS_rforkall
2020 || scno == SYS_rforkall
2021#endif /* SYS_rforkall */
2022 ) {
2023 /* We are returning in the child, fake it. */
2024 tcp->status.PR_WHY = PR_SYSENTRY;
2025 trace_syscall(tcp);
2026 tcp->status.PR_WHY = PR_SYSEXIT;
2027 }
2028 else {
2029 fprintf(stderr, "syscall: missing entry\n");
2030 tcp->flags |= TCB_INSYSCALL;
2031 }
2032 }
2033 }
2034 else {
2035 if (tcp->status.PR_WHY != PR_SYSEXIT) {
2036 fprintf(stderr, "syscall: missing exit\n");
2037 tcp->flags &= ~TCB_INSYSCALL;
2038 }
2039 }
2040#endif /* USE_PROCFS */
2041
2042#ifdef SUNOS4
2043 if (entering(tcp)) {
2044 if (scno == 0) {
2045 fprintf(stderr, "syscall: missing entry\n");
2046 tcp->flags |= TCB_INSYSCALL;
2047 }
2048 }
2049 else {
2050 if (scno != 0) {
2051 if (debug) {
2052 /*
2053 * This happens when a signal handler
2054 * for a signal which interrupted a
2055 * a system call makes another system call.
2056 */
2057 fprintf(stderr, "syscall: missing exit\n");
2058 }
2059 tcp->flags &= ~TCB_INSYSCALL;
2060 }
2061 }
2062#endif /* SUNOS4 */
2063
2064#ifdef LINUX
2065 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
2066#if defined (I386)
2067 /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
2068 * Every extra ptrace call is expensive, so check EAX
2069 * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
2070 */
2071 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
2072 if (upeek(tcp, 4*EAX, &eax) < 0)
2073 return -1;
2074 if (eax != -ENOSYS) {
2075 if (debug)
2076 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
2077 return 0;
2078 }
2079 }
2080#elif defined (X86_64)
2081 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
2082 if (upeek(tcp, 8*RAX, &rax) < 0)
2083 return -1;
2084 if (current_personality == 1)
2085 rax = (long int)(int)rax; /* sign extend from 32 bits */
2086 if (rax != -ENOSYS && entering(tcp)) {
2087 if (debug)
2088 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
2089 return 0;
2090 }
2091 }
2092#elif defined (S390) || defined (S390X)
2093 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
2094 return -1;
2095 if (syscall_mode != -ENOSYS)
2096 syscall_mode = tcp->scno;
2097 if (gpr2 != syscall_mode && entering(tcp)) {
2098 if (debug)
2099 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
2100 return 0;
2101 }
2102 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
2103 == (TCB_INSYSCALL|TCB_WAITEXECVE))
2104 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2105 /*
2106 * Return from execve.
2107 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2108 * flag set for the post-execve SIGTRAP to see and reset.
2109 */
2110 gpr2 = 0;
2111 }
2112#elif defined (POWERPC)
2113# define SO_MASK 0x10000000
2114 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
2115 return -1;
2116 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
2117 return -1;
2118 if (flags & SO_MASK)
2119 result = -result;
2120#elif defined (M68K)
2121 if (upeek(tcp, 4*PT_D0, &d0) < 0)
2122 return -1;
2123 if (d0 != -ENOSYS && entering(tcp)) {
2124 if (debug)
2125 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
2126 return 0;
2127 }
2128#elif defined (ARM)
2129 /*
2130 * Nothing required
2131 */
2132#elif defined(BFIN)
2133 if (upeek(tcp, PT_R0, &r0) < 0)
2134 return -1;
2135#elif defined (HPPA)
2136 if (upeek(tcp, PT_GR28, &r28) < 0)
2137 return -1;
2138#elif defined(IA64)
2139 if (upeek(tcp, PT_R10, &r10) < 0)
2140 return -1;
2141 if (upeek(tcp, PT_R8, &r8) < 0)
2142 return -1;
2143 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
2144 if (debug)
2145 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
2146 return 0;
2147 }
2148#elif defined(CRISV10) || defined(CRISV32)
2149 if (upeek(tcp, 4*PT_R10, &r10) < 0)
2150 return -1;
2151 if (r10 != -ENOSYS && entering(tcp)) {
2152 if (debug)
2153 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
2154 return 0;
2155 }
2156#elif defined(MICROBLAZE)
2157 if (upeek(tcp, 3 * 4, &r3) < 0)
2158 return -1;
2159 if (r3 != -ENOSYS && entering(tcp)) {
2160 if (debug)
2161 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
2162 return 0;
2163 }
2164#endif
2165#endif /* LINUX */
2166 return 1;
2167}
2168
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002169#ifdef LINUX
2170/*
2171 * Check the syscall return value register value for whether it is
2172 * a negated errno code indicating an error, or a success return value.
2173 */
2174static inline int
2175is_negated_errno(unsigned long int val)
2176{
2177 unsigned long int max = -(long int) nerrnos;
2178# if SUPPORTED_PERSONALITIES > 1
2179 if (personality_wordsize[current_personality] < sizeof(val)) {
2180 val = (unsigned int) val;
2181 max = (unsigned int) max;
2182 }
2183# endif
2184 return val > max;
2185}
2186#endif
2187
2188static int
2189get_error(struct tcb *tcp)
2190{
2191 int u_error = 0;
2192#ifdef LINUX
2193 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002194 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002195 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2196 check_errno = 0;
2197 }
2198# if defined(S390) || defined(S390X)
2199 if (check_errno && is_negated_errno(gpr2)) {
2200 tcp->u_rval = -1;
2201 u_error = -gpr2;
2202 }
2203 else {
2204 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002205 }
2206# elif defined(I386)
2207 if (check_errno && is_negated_errno(eax)) {
2208 tcp->u_rval = -1;
2209 u_error = -eax;
2210 }
2211 else {
2212 tcp->u_rval = eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002213 }
2214# elif defined(X86_64)
2215 if (check_errno && is_negated_errno(rax)) {
2216 tcp->u_rval = -1;
2217 u_error = -rax;
2218 }
2219 else {
2220 tcp->u_rval = rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002221 }
2222# elif defined(IA64)
2223 if (ia32) {
2224 int err;
2225
2226 err = (int)r8;
2227 if (check_errno && is_negated_errno(err)) {
2228 tcp->u_rval = -1;
2229 u_error = -err;
2230 }
2231 else {
2232 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002233 }
2234 } else {
2235 if (check_errno && r10) {
2236 tcp->u_rval = -1;
2237 u_error = r8;
2238 } else {
2239 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002240 }
2241 }
2242# elif defined(MIPS)
2243 if (check_errno && a3) {
2244 tcp->u_rval = -1;
2245 u_error = r2;
2246 } else {
2247 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002248 }
2249# elif defined(POWERPC)
2250 if (check_errno && is_negated_errno(result)) {
2251 tcp->u_rval = -1;
2252 u_error = -result;
2253 }
2254 else {
2255 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002256 }
2257# elif defined(M68K)
2258 if (check_errno && is_negated_errno(d0)) {
2259 tcp->u_rval = -1;
2260 u_error = -d0;
2261 }
2262 else {
2263 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002264 }
2265# elif defined(ARM)
2266 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2267 tcp->u_rval = -1;
2268 u_error = -regs.ARM_r0;
2269 }
2270 else {
2271 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002272 }
2273# elif defined(AVR32)
2274 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2275 tcp->u_rval = -1;
2276 u_error = -regs.r12;
2277 }
2278 else {
2279 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002280 }
2281# elif defined(BFIN)
2282 if (check_errno && is_negated_errno(r0)) {
2283 tcp->u_rval = -1;
2284 u_error = -r0;
2285 } else {
2286 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002287 }
2288# elif defined(ALPHA)
2289 if (check_errno && a3) {
2290 tcp->u_rval = -1;
2291 u_error = r0;
2292 }
2293 else {
2294 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002295 }
2296# elif defined(SPARC)
2297 if (check_errno && regs.psr & PSR_C) {
2298 tcp->u_rval = -1;
2299 u_error = regs.u_regs[U_REG_O0];
2300 }
2301 else {
2302 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002303 }
2304# elif defined(SPARC64)
2305 if (check_errno && regs.tstate & 0x1100000000UL) {
2306 tcp->u_rval = -1;
2307 u_error = regs.u_regs[U_REG_O0];
2308 }
2309 else {
2310 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002311 }
2312# elif defined(HPPA)
2313 if (check_errno && is_negated_errno(r28)) {
2314 tcp->u_rval = -1;
2315 u_error = -r28;
2316 }
2317 else {
2318 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002319 }
2320# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002321 if (check_errno && is_negated_errno(r0)) {
2322 tcp->u_rval = -1;
2323 u_error = -r0;
2324 }
2325 else {
2326 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002327 }
2328# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002329 if (check_errno && is_negated_errno(r9)) {
2330 tcp->u_rval = -1;
2331 u_error = -r9;
2332 }
2333 else {
2334 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002335 }
2336# elif defined(CRISV10) || defined(CRISV32)
2337 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2338 tcp->u_rval = -1;
2339 u_error = -r10;
2340 }
2341 else {
2342 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002343 }
2344# elif defined(TILE)
2345 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002346 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2347 return -1;
2348 if (check_errno && rval < 0 && rval > -nerrnos) {
2349 tcp->u_rval = -1;
2350 u_error = -rval;
2351 }
2352 else {
2353 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002354 }
2355# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002356 if (check_errno && is_negated_errno(r3)) {
2357 tcp->u_rval = -1;
2358 u_error = -r3;
2359 }
2360 else {
2361 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002362 }
2363# endif
2364#endif /* LINUX */
2365#ifdef SUNOS4
2366 /* get error code from user struct */
2367 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2368 return -1;
2369 u_error >>= 24; /* u_error is a char */
2370
2371 /* get system call return value */
2372 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2373 return -1;
2374#endif /* SUNOS4 */
2375#ifdef SVR4
2376# ifdef SPARC
2377 /* Judicious guessing goes a long way. */
2378 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2379 tcp->u_rval = -1;
2380 u_error = tcp->status.pr_reg[R_O0];
2381 }
2382 else {
2383 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002384 }
2385# endif /* SPARC */
2386# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002387 if (tcp->status.PR_REG[EFL] & 0x1) {
2388 tcp->u_rval = -1;
2389 u_error = tcp->status.PR_REG[EAX];
2390 }
2391 else {
2392 tcp->u_rval = tcp->status.PR_REG[EAX];
2393# ifdef HAVE_LONG_LONG
2394 tcp->u_lrval =
2395 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2396 tcp->status.PR_REG[EAX];
2397# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002398 }
2399# endif /* I386 */
2400# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002401 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2402 tcp->u_rval = -1;
2403 u_error = tcp->status.PR_REG[RAX];
2404 }
2405 else {
2406 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002407 }
2408# endif /* X86_64 */
2409# ifdef MIPS
2410 if (tcp->status.pr_reg[CTX_A3]) {
2411 tcp->u_rval = -1;
2412 u_error = tcp->status.pr_reg[CTX_V0];
2413 }
2414 else {
2415 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002416 }
2417# endif /* MIPS */
2418#endif /* SVR4 */
2419#ifdef FREEBSD
2420 if (regs.r_eflags & PSL_C) {
2421 tcp->u_rval = -1;
2422 u_error = regs.r_eax;
2423 } else {
2424 tcp->u_rval = regs.r_eax;
2425 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002426 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002427 }
2428#endif /* FREEBSD */
2429 tcp->u_error = u_error;
2430 return 1;
2431}
2432
2433static void
2434dumpio(struct tcb *tcp)
2435{
2436 if (syserror(tcp))
2437 return;
2438 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2439 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002440 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002441 return;
2442 if (sysent[tcp->scno].sys_func == printargs)
2443 return;
2444 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2445 if (sysent[tcp->scno].sys_func == sys_read ||
2446 sysent[tcp->scno].sys_func == sys_pread ||
2447 sysent[tcp->scno].sys_func == sys_pread64 ||
2448 sysent[tcp->scno].sys_func == sys_recv ||
2449 sysent[tcp->scno].sys_func == sys_recvfrom)
2450 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2451 else if (sysent[tcp->scno].sys_func == sys_readv)
2452 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2453 return;
2454 }
2455 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2456 if (sysent[tcp->scno].sys_func == sys_write ||
2457 sysent[tcp->scno].sys_func == sys_pwrite ||
2458 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2459 sysent[tcp->scno].sys_func == sys_send ||
2460 sysent[tcp->scno].sys_func == sys_sendto)
2461 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2462 else if (sysent[tcp->scno].sys_func == sys_writev)
2463 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2464 return;
2465 }
2466}
2467
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002468static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002469trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002470{
2471 int sys_res;
2472 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002473 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002474 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002475
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002476 /* Measure the exit time as early as possible to avoid errors. */
2477 if (dtime || cflag)
2478 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002479
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002480 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002481 if (res == 0)
2482 return res;
2483 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002484 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002485 if (res == 0)
2486 return res;
2487 if (res == 1)
2488 res = get_error(tcp);
2489 if (res == 0)
2490 return res;
2491 if (res == 1)
2492 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002493
Grant Edwards8a082772011-04-07 20:25:40 +00002494 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002495 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002496 }
2497
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002498 if (tcp->flags & TCB_REPRINT) {
2499 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002500 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002501 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002502 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002503 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002504 }
2505
2506 if (cflag) {
2507 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002508 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002509 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002510 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002511 }
2512 }
2513
2514 if (res != 1) {
2515 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002516 tabto();
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002517 tprintf("= ? <unavailable>");
2518 printtrailer();
2519 tcp->flags &= ~TCB_INSYSCALL;
2520 return res;
2521 }
2522
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002523 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002524 || (qual_flags[tcp->scno] & QUAL_RAW))
2525 sys_res = printargs(tcp);
2526 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002527 /* FIXME: not_failing_only (IOW, option -z) is broken:
2528 * failure of syscall is known only after syscall return.
2529 * Thus we end up with something like this on, say, ENOENT:
2530 * open("doesnt_exist", O_RDONLY <unfinished ...>
2531 * {next syscall decode}
2532 * whereas the intended result is that open(...) line
2533 * is not shown at all.
2534 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002535 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002536 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002537 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2538 }
2539
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002540 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002541 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002542 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002543 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002544 qual_flags[tcp->scno] & QUAL_RAW) {
2545 if (u_error)
2546 tprintf("= -1 (errno %ld)", u_error);
2547 else
2548 tprintf("= %#lx", tcp->u_rval);
2549 }
2550 else if (!(sys_res & RVAL_NONE) && u_error) {
2551 switch (u_error) {
2552#ifdef LINUX
2553 case ERESTARTSYS:
2554 tprintf("= ? ERESTARTSYS (To be restarted)");
2555 break;
2556 case ERESTARTNOINTR:
2557 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2558 break;
2559 case ERESTARTNOHAND:
2560 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2561 break;
2562 case ERESTART_RESTARTBLOCK:
2563 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2564 break;
2565#endif /* LINUX */
2566 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002567 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002568 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002569 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002570 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002571 strerror(u_error));
2572 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002573 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002574 strerror(u_error));
2575 break;
2576 }
2577 if ((sys_res & RVAL_STR) && tcp->auxstr)
2578 tprintf(" (%s)", tcp->auxstr);
2579 }
2580 else {
2581 if (sys_res & RVAL_NONE)
2582 tprintf("= ?");
2583 else {
2584 switch (sys_res & RVAL_MASK) {
2585 case RVAL_HEX:
2586 tprintf("= %#lx", tcp->u_rval);
2587 break;
2588 case RVAL_OCTAL:
2589 tprintf("= %#lo", tcp->u_rval);
2590 break;
2591 case RVAL_UDECIMAL:
2592 tprintf("= %lu", tcp->u_rval);
2593 break;
2594 case RVAL_DECIMAL:
2595 tprintf("= %ld", tcp->u_rval);
2596 break;
2597#ifdef HAVE_LONG_LONG
2598 case RVAL_LHEX:
2599 tprintf("= %#llx", tcp->u_lrval);
2600 break;
2601 case RVAL_LOCTAL:
2602 tprintf("= %#llo", tcp->u_lrval);
2603 break;
2604 case RVAL_LUDECIMAL:
2605 tprintf("= %llu", tcp->u_lrval);
2606 break;
2607 case RVAL_LDECIMAL:
2608 tprintf("= %lld", tcp->u_lrval);
2609 break;
2610#endif
2611 default:
2612 fprintf(stderr,
2613 "invalid rval format\n");
2614 break;
2615 }
2616 }
2617 if ((sys_res & RVAL_STR) && tcp->auxstr)
2618 tprintf(" (%s)", tcp->auxstr);
2619 }
2620 if (dtime) {
2621 tv_sub(&tv, &tv, &tcp->etime);
2622 tprintf(" <%ld.%06ld>",
2623 (long) tv.tv_sec, (long) tv.tv_usec);
2624 }
2625 printtrailer();
2626
2627 dumpio(tcp);
2628 if (fflush(tcp->outf) == EOF)
2629 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002630 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002631 tcp->flags &= ~TCB_INSYSCALL;
2632 return 0;
2633}
2634
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002636trace_syscall(struct tcb *tcp)
2637{
2638 return exiting(tcp) ?
2639 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2640}