blob: 89861ad0398c73b41cb474ee305291079b6e4602 [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)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200719static struct pt_regs i386_regs;
720# elif defined(X86_64)
721static struct pt_regs x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200722# elif defined (IA64)
723long r8, r10, psr; /* TODO: make static? */
724long ia32 = 0; /* not static */
725# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200726static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200727# elif defined (M68K)
728static long d0;
729# elif defined(BFIN)
730static long r0;
731# elif defined (ARM)
732static struct pt_regs regs;
733# elif defined (ALPHA)
734static long r0;
735static long a3;
736# elif defined(AVR32)
737static struct pt_regs regs;
738# elif defined (SPARC) || defined (SPARC64)
739static struct pt_regs regs;
740static unsigned long trap;
741# elif defined(LINUX_MIPSN32)
742static long long a3;
743static long long r2;
744# elif defined(MIPS)
745static long a3;
746static long r2;
747# elif defined(S390) || defined(S390X)
748static long gpr2;
749static long pc;
750static long syscall_mode;
751# elif defined(HPPA)
752static long r28;
753# elif defined(SH)
754static long r0;
755# elif defined(SH64)
756static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200757# 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 Vlasenkoeb0e3e82011-08-30 18:53:49 +0200898 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200900 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000901# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200902 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200903 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
904 return -1;
905 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000906
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200907 /* Check CS register value. On x86-64 linux it is:
908 * 0x33 for long mode (64 bit)
909 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200910 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200911 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200912 case 0x23: currpers = 1; break;
913 case 0x33: currpers = 0; break;
914 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200915 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200916 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200917 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200918 currpers = current_personality;
919 break;
920 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000921# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200922 /* This version analyzes the opcode of a syscall instruction.
923 * (int 0x80 on i386 vs. syscall on x86-64)
924 * It works, but is too complicated.
925 */
926 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000927
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200928 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000929
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
931 rip -= 2;
932 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000933
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200934 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200935 if (errno)
936 fprintf(stderr, "ptrace_peektext failed: %s\n",
937 strerror(errno));
938 switch (call & 0xffff) {
939 /* x86-64: syscall = 0x0f 0x05 */
940 case 0x050f: currpers = 0; break;
941 /* i386: int 0x80 = 0xcd 0x80 */
942 case 0x80cd: currpers = 1; break;
943 default:
944 currpers = current_personality;
945 fprintf(stderr,
946 "Unknown syscall opcode (0x%04X) while "
947 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200948 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200949 break;
950 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000951# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200952 if (currpers != current_personality) {
953 static const char *const names[] = {"64 bit", "32 bit"};
954 set_personality(currpers);
955 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200956 tcp->pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000957 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000958# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000959# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200960 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000961 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200962 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200963 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200964 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000965 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200966 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000967 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200968 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000969# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200970 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000971 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000972 return -1;
973
974 /*
975 * We only need to grab the syscall number on syscall entry.
976 */
977 if (regs.ARM_ip == 0) {
978 /*
979 * Note: we only deal with only 32-bit CPUs here.
980 */
981 if (regs.ARM_cpsr & 0x20) {
982 /*
983 * Get the Thumb-mode system call number
984 */
985 scno = regs.ARM_r7;
986 } else {
987 /*
988 * Get the ARM-mode system call number
989 */
990 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000991 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000992 if (errno)
993 return -1;
994
Roland McGrathf691bd22006-04-25 07:34:41 +0000995 /* Handle the EABI syscall convention. We do not
996 bother converting structures between the two
997 ABIs, but basic functionality should work even
998 if strace and the traced program have different
999 ABIs. */
1000 if (scno == 0xef000000) {
1001 scno = regs.ARM_r7;
1002 } else {
1003 if ((scno & 0x0ff00000) != 0x0f900000) {
1004 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1005 scno);
1006 return -1;
1007 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001008
Roland McGrathf691bd22006-04-25 07:34:41 +00001009 /*
1010 * Fixup the syscall number
1011 */
1012 scno &= 0x000fffff;
1013 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 }
Roland McGrath56703312008-05-20 01:35:55 +00001015 if (scno & 0x0f0000) {
1016 /*
1017 * Handle ARM specific syscall
1018 */
1019 set_personality(1);
1020 scno &= 0x0000ffff;
1021 } else
1022 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001023
Roland McGrath0f87c492003-06-03 23:29:04 +00001024 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001025 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1026 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001028# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001029 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001031# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001032 unsigned long long regs[38];
1033
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001034 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001035 return -1;
1036 a3 = regs[REG_A3];
1037 r2 = regs[REG_V0];
1038
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001039 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001040 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001041 if (a3 == 0 || a3 == -1) {
1042 if (debug)
1043 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001044 return 0;
1045 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001046 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001047# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001048 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001049 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001050 if (upeek(tcp, REG_V0, &scno) < 0)
1051 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001052
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001053 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001054 if (a3 == 0 || a3 == -1) {
1055 if (debug)
1056 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001057 return 0;
1058 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001059 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001060# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001061 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 if (upeek(tcp, REG_R0, &scno) < 0)
1064 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001066 /*
1067 * Do some sanity checks to figure out if it's
1068 * really a syscall entry
1069 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001070 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001071 if (a3 == 0 || a3 == -1) {
1072 if (debug)
1073 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 return 0;
1075 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001077# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001079 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080 return -1;
1081
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001082 /* Disassemble the syscall trap. */
1083 /* Retrieve the syscall trap instruction. */
1084 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001085# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001086 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1087 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001088# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001089 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001090# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001091 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001092 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001093
1094 /* Disassemble the trap to see what personality to use. */
1095 switch (trap) {
1096 case 0x91d02010:
1097 /* Linux/SPARC syscall trap. */
1098 set_personality(0);
1099 break;
1100 case 0x91d0206d:
1101 /* Linux/SPARC64 syscall trap. */
1102 set_personality(2);
1103 break;
1104 case 0x91d02000:
1105 /* SunOS syscall trap. (pers 1) */
1106 fprintf(stderr, "syscall: SunOS no support\n");
1107 return -1;
1108 case 0x91d02008:
1109 /* Solaris 2.x syscall trap. (per 2) */
1110 set_personality(1);
1111 break;
1112 case 0x91d02009:
1113 /* NetBSD/FreeBSD syscall trap. */
1114 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1115 return -1;
1116 case 0x91d02027:
1117 /* Solaris 2.x gettimeofday */
1118 set_personality(1);
1119 break;
1120 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001121# if defined (SPARC64)
1122 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1123# else
1124 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1125# endif
1126 return -1;
1127 }
1128
1129 /* Extract the system call number from the registers. */
1130 if (trap == 0x91d02027)
1131 scno = 156;
1132 else
1133 scno = regs.u_regs[U_REG_G1];
1134 if (scno == 0) {
1135 scno = regs.u_regs[U_REG_O0];
1136 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1137 }
1138# elif defined(HPPA)
1139 if (upeek(tcp, PT_GR20, &scno) < 0)
1140 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001141# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001142 /*
1143 * In the new syscall ABI, the system call number is in R3.
1144 */
1145 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1146 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001147
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001148 if (scno < 0) {
1149 /* Odd as it may seem, a glibc bug has been known to cause
1150 glibc to issue bogus negative syscall numbers. So for
1151 our purposes, make strace print what it *should* have been */
1152 long correct_scno = (scno & 0xff);
1153 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001154 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001155 "Detected glibc bug: bogus system call"
1156 " number = %ld, correcting to %ld\n",
1157 scno,
1158 correct_scno);
1159 scno = correct_scno;
1160 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001161# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001162 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001163 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001164 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001165# elif defined(CRISV10) || defined(CRISV32)
1166 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1167 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001168# elif defined(TILE)
1169 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1170 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001171# elif defined(MICROBLAZE)
1172 if (upeek(tcp, 0, &scno) < 0)
1173 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001180#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001181 /* new syscall ABI returns result in R0 */
1182 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1183 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001184#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001185 /* ABI defines result returned in r9 */
1186 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1187 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001190#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001191# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001192 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001193# else
1194# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001195 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001196# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001197 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001198 perror("pread");
1199 return -1;
1200 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001201 switch (regs.r_eax) {
1202 case SYS_syscall:
1203 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001204 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1205 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001206 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001207 scno = regs.r_eax;
1208 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001209 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001210# endif /* FREEBSD */
1211# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001212#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001213
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001214 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001215 return 1;
1216}
1217
Roland McGrath17352792005-06-07 23:21:26 +00001218long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001219known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001220{
1221 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001222#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001223 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001224 scno = sysent[scno].native_scno;
1225 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001226#endif
Roland McGrath17352792005-06-07 23:21:26 +00001227 scno += NR_SYSCALL_BASE;
1228 return scno;
1229}
1230
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001231/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001232 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001233 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001234 * 1: ok, continue in trace_syscall().
1235 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001236 * ("????" etc) and bail out.
1237 */
Roland McGratha4d48532005-06-08 20:45:28 +00001238static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001239syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001240{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001241#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001242 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001243
Denys Vlasenkoece98792011-08-25 10:25:35 +02001244 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1245 if (
1246 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001248 || scno == SYS_vfork
1249#endif
John Hughes4e36a812001-04-18 15:11:51 +00001250#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001251 || scno == SYS_fork1
1252#endif
John Hughes4e36a812001-04-18 15:11:51 +00001253#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001254 || scno == SYS_forkall
1255#endif
John Hughes4e36a812001-04-18 15:11:51 +00001256#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001257 || scno == SYS_rfork1
1258#endif
John Hughes4e36a812001-04-18 15:11:51 +00001259#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001260 || scno == SYS_rforkall
1261#endif
1262 ) {
1263 /* We are returning in the child, fake it. */
1264 tcp->status.PR_WHY = PR_SYSENTRY;
1265 trace_syscall(tcp);
1266 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001268 else {
1269 fprintf(stderr, "syscall: missing entry\n");
1270 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 }
1272 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001273#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001274
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001276 if (scno == 0) {
1277 fprintf(stderr, "syscall: missing entry\n");
1278 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001280#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001281
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001283 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001285 if (i386_regs.eax != -ENOSYS) {
1286 if (debug)
1287 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1288 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001290#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001291 {
1292 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001293 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001294 rax = (int)rax; /* sign extend from 32 bits */
1295 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001296 if (debug)
1297 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1298 return 0;
1299 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001300 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001301#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001302 /* TODO: we already fetched PT_GPR2 in get_scno
1303 * and stored it in syscall_mode, reuse it here
1304 * instead of re-fetching?
1305 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001306 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001307 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001308 if (syscall_mode != -ENOSYS)
1309 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001310 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001311 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001312 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001313 return 0;
1314 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001316 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001317 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001319 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001321 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001322 return 0;
1323 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001324#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001325 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001326 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001327 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001328 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001329 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001330 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001331 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001332 return 0;
1333 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001334#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001335 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001336 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001337 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001338 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001339 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001340 return 0;
1341 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001342#elif defined(MICROBLAZE)
1343 if (upeek(tcp, 3 * 4, &r3) < 0)
1344 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001345 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001346 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001347 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001348 return 0;
1349 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350#endif
1351#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001352 return 1;
1353}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001355static int
1356internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001357{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001358 /*
1359 * We must always trace a few critical system calls in order to
1360 * correctly support following forks in the presence of tracing
1361 * qualifiers.
1362 */
1363 int (*func)();
1364
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001365 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001366 return 0;
1367
1368 func = sysent[tcp->scno].sys_func;
1369
1370 if ( sys_fork == func
1371#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1372 || sys_vfork == func
1373#endif
1374#ifdef LINUX
1375 || sys_clone == func
1376#endif
1377#if UNIXWARE > 2
1378 || sys_rfork == func
1379#endif
1380 )
1381 return internal_fork(tcp);
1382
1383#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1384 if ( sys_execve == func
1385# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1386 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001387# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001388# if UNIXWARE > 2
1389 || sys_rexecve == func
1390# endif
1391 )
1392 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001393#endif
1394
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001395 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001396}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397
Roland McGratha4d48532005-06-08 20:45:28 +00001398static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001399syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001400{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001401#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001402 int i, nargs;
1403
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001404 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001405 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001406 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001407 nargs = tcp->u_nargs = MAX_ARGS;
1408
1409# if defined(S390) || defined(S390X)
1410 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001411 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1412 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001413# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001414 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001415 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1416 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001417# elif defined(IA64)
1418 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001419 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001420 long rbs_end;
1421 /* be backwards compatible with kernel < 2.4.4... */
1422# ifndef PT_RBS_END
1423# define PT_RBS_END PT_AR_BSP
1424# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001425
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1427 return -1;
1428 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001429 return -1;
1430
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001431 sof = (cfm >> 0) & 0x7f;
1432 sol = (cfm >> 7) & 0x7f;
1433 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1434
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001435 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001436 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1437 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1438 return -1;
1439 }
1440 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001441 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1442 PT_R9 /* ECX = out1 */,
1443 PT_R10 /* EDX = out2 */,
1444 PT_R14 /* ESI = out3 */,
1445 PT_R15 /* EDI = out4 */,
1446 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001447
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001448 for (i = 0; i < nargs; ++i) {
1449 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1450 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001451 /* truncate away IVE sign-extension */
1452 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001453 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001454 }
1455# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1456 /* N32 and N64 both use up to six registers. */
1457 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001458
1459 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1460 return -1;
1461
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001462 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001463 tcp->u_arg[i] = regs[REG_A0 + i];
1464# if defined(LINUX_MIPSN32)
1465 tcp->ext_arg[i] = regs[REG_A0 + i];
1466# endif
1467 }
1468# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001469 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001470 long sp;
1471
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001472 if (upeek(tcp, REG_SP, &sp) < 0)
1473 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001474 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001475 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1476 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001477 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001478 (char *)(tcp->u_arg + 4));
1479 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001480 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001481 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001484# elif defined(POWERPC)
1485# ifndef PT_ORIG_R3
1486# define PT_ORIG_R3 34
1487# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001488 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001489 if (upeek(tcp, (i==0) ?
1490 (sizeof(unsigned long) * PT_ORIG_R3) :
1491 ((i+PT_R3) * sizeof(unsigned long)),
1492 &tcp->u_arg[i]) < 0)
1493 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001495# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001496 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001497 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1498# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001499 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001500 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1501 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001502# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001503 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001504 tcp->u_arg[i] = regs.uregs[i];
1505# elif defined(AVR32)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001506 /* TODO: make it faster by unrolling into 6 direct assignments */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001507 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
1508 &regs.r11,
1509 &regs.r10,
1510 &regs.r9,
1511 &regs.r5,
1512 &regs.r3 };
1513 for (i = 0; i < nargs; ++i)
1514 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001515# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001516 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 +02001517
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001518 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001519 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1520 return -1;
1521# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001522 static const int syscall_regs[MAX_ARGS] = {
1523 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1524 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001525 };
1526
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001527 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001528 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001529 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001530# elif defined(SH64)
1531 int i;
1532 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001533 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001534
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001535 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001536 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1537 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001538# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001539 (void)i;
1540 (void)nargs;
1541 if (current_personality == 0) { /* x86-64 ABI */
1542 tcp->u_arg[0] = x86_64_regs.rdi;
1543 tcp->u_arg[1] = x86_64_regs.rsi;
1544 tcp->u_arg[2] = x86_64_regs.rdx;
1545 tcp->u_arg[3] = x86_64_regs.r10;
1546 tcp->u_arg[4] = x86_64_regs.r8;
1547 tcp->u_arg[5] = x86_64_regs.r9;
1548 } else { /* i386 ABI */
1549 /* Sign-extend lower 32 bits */
1550 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1551 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1552 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1553 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1554 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1555 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1556 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001557# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001558 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001559 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1560 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001561# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001562 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001563 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001564 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001565 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001566
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001567 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001568 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1569 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001570# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001571 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001572 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1573 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001574# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001575 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001576 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1577 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001578# elif defined(I386)
1579 (void)i;
1580 (void)nargs;
1581 tcp->u_arg[0] = i386_regs.ebx;
1582 tcp->u_arg[1] = i386_regs.ecx;
1583 tcp->u_arg[2] = i386_regs.edx;
1584 tcp->u_arg[3] = i386_regs.esi;
1585 tcp->u_arg[4] = i386_regs.edi;
1586 tcp->u_arg[5] = i386_regs.ebp;
1587# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001588 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001589 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1590 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001591# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592#endif /* LINUX */
1593#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001594 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001595 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001596 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001597 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001598 nargs = tcp->u_nargs = MAX_ARGS;
1599 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001600 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001602 if (upeek(tcp, uoff(u_arg[0]) +
1603 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1604 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 }
1606#endif /* SUNOS4 */
1607#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001608# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609 /*
1610 * SGI is broken: even though it has pr_sysarg, it doesn't
1611 * set them on system call entry. Get a clue.
1612 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001613 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 tcp->u_nargs = sysent[tcp->scno].nargs;
1615 else
1616 tcp->u_nargs = tcp->status.pr_nsysarg;
1617 if (tcp->u_nargs > 4) {
1618 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001619 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001621 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 }
1623 else {
1624 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001625 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001627# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001628 /*
1629 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1630 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001631 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001632 tcp->u_nargs = sysent[tcp->scno].nargs;
1633 else
1634 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1635 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001636 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1637# elif defined(HAVE_PR_SYSCALL)
1638 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001639 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640 tcp->u_nargs = sysent[tcp->scno].nargs;
1641 else
1642 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001643 for (i = 0; i < tcp->u_nargs; i++)
1644 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1645# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001646 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 tcp->u_nargs = sysent[tcp->scno].nargs;
1648 else
1649 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001650 if (tcp->u_nargs > 0)
1651 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001652 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1653# else
John Hughes25299712001-03-06 10:10:06 +00001654 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001655# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001657#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001658 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001659 sysent[tcp->scno].nargs > tcp->status.val)
1660 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001661 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001662 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001663 if (tcp->u_nargs < 0)
1664 tcp->u_nargs = 0;
1665 if (tcp->u_nargs > MAX_ARGS)
1666 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001667 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001668 case SYS___syscall:
1669 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1670 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001671 break;
1672 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001673 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1674 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001675 break;
1676 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001677 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1678 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001679 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001680 }
1681#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001682 return 1;
1683}
1684
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001685static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001686trace_syscall_entering(struct tcb *tcp)
1687{
1688 int res, scno_good;
1689
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001690#if defined TCB_WAITEXECVE
1691 if (tcp->flags & TCB_WAITEXECVE) {
1692 /* This is the post-execve SIGTRAP. */
1693 tcp->flags &= ~TCB_WAITEXECVE;
1694 return 0;
1695 }
1696#endif
1697
Denys Vlasenko06602d92011-08-24 17:53:52 +02001698 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001699 if (res == 0)
1700 return res;
1701 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001702 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001703 if (res == 0)
1704 return res;
1705 if (res == 1)
1706 res = syscall_enter(tcp);
1707 if (res == 0)
1708 return res;
1709
1710 if (res != 1) {
1711 printleader(tcp);
1712 tcp->flags &= ~TCB_REPRINT;
1713 tcp_last = tcp;
1714 if (scno_good != 1)
1715 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001716 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001717 tprintf("syscall_%lu(", tcp->scno);
1718 else
1719 tprintf("%s(", sysent[tcp->scno].sys_name);
1720 /*
1721 * " <unavailable>" will be added later by the code which
1722 * detects ptrace errors.
1723 */
1724 goto ret;
1725 }
1726
1727 switch (known_scno(tcp)) {
1728#ifdef SYS_socket_subcall
1729 case SYS_socketcall:
1730 decode_subcall(tcp, SYS_socket_subcall,
1731 SYS_socket_nsubcalls, deref_style);
1732 break;
1733#endif
1734#ifdef SYS_ipc_subcall
1735 case SYS_ipc:
1736 decode_subcall(tcp, SYS_ipc_subcall,
1737 SYS_ipc_nsubcalls, shift_style);
1738 break;
1739#endif
1740#ifdef SVR4
1741#ifdef SYS_pgrpsys_subcall
1742 case SYS_pgrpsys:
1743 decode_subcall(tcp, SYS_pgrpsys_subcall,
1744 SYS_pgrpsys_nsubcalls, shift_style);
1745 break;
1746#endif /* SYS_pgrpsys_subcall */
1747#ifdef SYS_sigcall_subcall
1748 case SYS_sigcall:
1749 decode_subcall(tcp, SYS_sigcall_subcall,
1750 SYS_sigcall_nsubcalls, mask_style);
1751 break;
1752#endif /* SYS_sigcall_subcall */
1753 case SYS_msgsys:
1754 decode_subcall(tcp, SYS_msgsys_subcall,
1755 SYS_msgsys_nsubcalls, shift_style);
1756 break;
1757 case SYS_shmsys:
1758 decode_subcall(tcp, SYS_shmsys_subcall,
1759 SYS_shmsys_nsubcalls, shift_style);
1760 break;
1761 case SYS_semsys:
1762 decode_subcall(tcp, SYS_semsys_subcall,
1763 SYS_semsys_nsubcalls, shift_style);
1764 break;
1765 case SYS_sysfs:
1766 decode_subcall(tcp, SYS_sysfs_subcall,
1767 SYS_sysfs_nsubcalls, shift_style);
1768 break;
1769 case SYS_spcall:
1770 decode_subcall(tcp, SYS_spcall_subcall,
1771 SYS_spcall_nsubcalls, shift_style);
1772 break;
1773#ifdef SYS_context_subcall
1774 case SYS_context:
1775 decode_subcall(tcp, SYS_context_subcall,
1776 SYS_context_nsubcalls, shift_style);
1777 break;
1778#endif /* SYS_context_subcall */
1779#ifdef SYS_door_subcall
1780 case SYS_door:
1781 decode_subcall(tcp, SYS_door_subcall,
1782 SYS_door_nsubcalls, door_style);
1783 break;
1784#endif /* SYS_door_subcall */
1785#ifdef SYS_kaio_subcall
1786 case SYS_kaio:
1787 decode_subcall(tcp, SYS_kaio_subcall,
1788 SYS_kaio_nsubcalls, shift_style);
1789 break;
1790#endif
1791#endif /* SVR4 */
1792#ifdef FREEBSD
1793 case SYS_msgsys:
1794 case SYS_shmsys:
1795 case SYS_semsys:
1796 decode_subcall(tcp, 0, 0, table_style);
1797 break;
1798#endif
1799#ifdef SUNOS4
1800 case SYS_semsys:
1801 decode_subcall(tcp, SYS_semsys_subcall,
1802 SYS_semsys_nsubcalls, shift_style);
1803 break;
1804 case SYS_msgsys:
1805 decode_subcall(tcp, SYS_msgsys_subcall,
1806 SYS_msgsys_nsubcalls, shift_style);
1807 break;
1808 case SYS_shmsys:
1809 decode_subcall(tcp, SYS_shmsys_subcall,
1810 SYS_shmsys_nsubcalls, shift_style);
1811 break;
1812#endif
1813 }
1814
1815 internal_syscall(tcp);
1816
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001817 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001818 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1819 (tracing_paths && !pathtrace_match(tcp))) {
1820 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1821 return 0;
1822 }
1823
1824 tcp->flags &= ~TCB_FILTERED;
1825
1826 if (cflag == CFLAG_ONLY_STATS) {
1827 res = 0;
1828 goto ret;
1829 }
1830
1831 printleader(tcp);
1832 tcp->flags &= ~TCB_REPRINT;
1833 tcp_last = tcp;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001834 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001835 tprintf("syscall_%lu(", tcp->scno);
1836 else
1837 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001838 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001839 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1840 sysent[tcp->scno].sys_func != sys_exit))
1841 res = printargs(tcp);
1842 else
1843 res = (*sysent[tcp->scno].sys_func)(tcp);
1844
1845 if (fflush(tcp->outf) == EOF)
1846 return -1;
1847 ret:
1848 tcp->flags |= TCB_INSYSCALL;
1849 /* Measure the entrance time as late as possible to avoid errors. */
1850 if (dtime || cflag)
1851 gettimeofday(&tcp->etime, NULL);
1852 return res;
1853}
1854
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001855/* Returns:
1856 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1857 * 1: ok, continue in trace_syscall().
1858 * other: error, trace_syscall() should print error indicator
1859 * ("????" etc) and bail out.
1860 */
1861static int
1862get_syscall_result(struct tcb *tcp)
1863{
1864#ifdef LINUX
1865# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001866 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1867 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001868# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001869# define SO_MASK 0x10000000
1870 {
1871 long flags;
1872 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1873 return -1;
1874 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1875 return -1;
1876 if (flags & SO_MASK)
1877 result = -result;
1878 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001879# elif defined(AVR32)
1880 /* Read complete register set in one go. */
1881 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1882 return -1;
1883# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001884 if (upeek(tcp, PT_R0, &r0) < 0)
1885 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001886# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001887 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001888 return -1;
1889# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001890 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001891 return -1;
1892# elif defined(IA64)
1893# define IA64_PSR_IS ((long)1 << 34)
1894 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1895 ia32 = (psr & IA64_PSR_IS) != 0;
1896 if (upeek(tcp, PT_R8, &r8) < 0)
1897 return -1;
1898 if (upeek(tcp, PT_R10, &r10) < 0)
1899 return -1;
1900# elif defined (ARM)
1901 /* Read complete register set in one go. */
1902 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1903 return -1;
1904# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001905 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1906 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001907# elif defined (LINUX_MIPSN32)
1908 unsigned long long regs[38];
1909
1910 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1911 return -1;
1912 a3 = regs[REG_A3];
1913 r2 = regs[REG_V0];
1914# elif defined (MIPS)
1915 if (upeek(tcp, REG_A3, &a3) < 0)
1916 return -1;
1917 if (upeek(tcp, REG_V0, &r2) < 0)
1918 return -1;
1919# elif defined (ALPHA)
1920 if (upeek(tcp, REG_A3, &a3) < 0)
1921 return -1;
1922 if (upeek(tcp, REG_R0, &r0) < 0)
1923 return -1;
1924# elif defined (SPARC) || defined (SPARC64)
1925 /* Everything we need is in the current register set. */
1926 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1927 return -1;
1928# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001929 if (upeek(tcp, PT_GR28, &r28) < 0)
1930 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001931# elif defined(SH)
1932# elif defined(SH64)
1933# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001934 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1935 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001936# elif defined(TILE)
1937# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001938 if (upeek(tcp, 3 * 4, &r3) < 0)
1939 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001940# endif
1941#endif /* LINUX */
1942
1943#ifdef SUNOS4
1944#elif defined(SH)
1945 /* new syscall ABI returns result in R0 */
1946 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1947 return -1;
1948#elif defined(SH64)
1949 /* ABI defines result returned in r9 */
1950 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1951 return -1;
1952#endif
1953
1954#ifdef USE_PROCFS
1955# ifndef HAVE_PR_SYSCALL
1956# ifdef FREEBSD
1957 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1958 perror("pread");
1959 return -1;
1960 }
1961# endif /* FREEBSD */
1962# endif /* !HAVE_PR_SYSCALL */
1963#endif /* USE_PROCFS */
1964
1965 return 1;
1966}
1967
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001968/* Called at each syscall exit.
1969 * Returns:
1970 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1971 * 1: ok, continue in trace_syscall().
1972 * other: error, trace_syscall() should print error indicator
1973 * ("????" etc) and bail out.
1974 */
1975static int
1976syscall_fixup_on_sysexit(struct tcb *tcp)
1977{
1978#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001979 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1980 fprintf(stderr, "syscall: missing exit\n");
1981 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001982 }
1983#endif /* USE_PROCFS */
1984
1985#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001986 {
1987 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001988 if (scno != 0) {
1989 if (debug) {
1990 /*
1991 * This happens when a signal handler
1992 * for a signal which interrupted a
1993 * a system call makes another system call.
1994 */
1995 fprintf(stderr, "syscall: missing exit\n");
1996 }
1997 tcp->flags &= ~TCB_INSYSCALL;
1998 }
1999 }
2000#endif /* SUNOS4 */
2001
2002#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002003# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002004 if (syscall_mode != -ENOSYS)
2005 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002006 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002007 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2008 /*
2009 * Return from execve.
2010 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2011 * flag set for the post-execve SIGTRAP to see and reset.
2012 */
2013 gpr2 = 0;
2014 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002015# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002016#endif /* LINUX */
2017 return 1;
2018}
2019
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002020#ifdef LINUX
2021/*
2022 * Check the syscall return value register value for whether it is
2023 * a negated errno code indicating an error, or a success return value.
2024 */
2025static inline int
2026is_negated_errno(unsigned long int val)
2027{
2028 unsigned long int max = -(long int) nerrnos;
2029# if SUPPORTED_PERSONALITIES > 1
2030 if (personality_wordsize[current_personality] < sizeof(val)) {
2031 val = (unsigned int) val;
2032 max = (unsigned int) max;
2033 }
2034# endif
2035 return val > max;
2036}
2037#endif
2038
2039static int
2040get_error(struct tcb *tcp)
2041{
2042 int u_error = 0;
2043#ifdef LINUX
2044 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002045 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002046 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2047 check_errno = 0;
2048 }
2049# if defined(S390) || defined(S390X)
2050 if (check_errno && is_negated_errno(gpr2)) {
2051 tcp->u_rval = -1;
2052 u_error = -gpr2;
2053 }
2054 else {
2055 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002056 }
2057# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002058 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002059 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002060 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002061 }
2062 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002063 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002064 }
2065# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002066 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002067 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002068 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002069 }
2070 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002071 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002072 }
2073# elif defined(IA64)
2074 if (ia32) {
2075 int err;
2076
2077 err = (int)r8;
2078 if (check_errno && is_negated_errno(err)) {
2079 tcp->u_rval = -1;
2080 u_error = -err;
2081 }
2082 else {
2083 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002084 }
2085 } else {
2086 if (check_errno && r10) {
2087 tcp->u_rval = -1;
2088 u_error = r8;
2089 } else {
2090 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002091 }
2092 }
2093# elif defined(MIPS)
2094 if (check_errno && a3) {
2095 tcp->u_rval = -1;
2096 u_error = r2;
2097 } else {
2098 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002099 }
2100# elif defined(POWERPC)
2101 if (check_errno && is_negated_errno(result)) {
2102 tcp->u_rval = -1;
2103 u_error = -result;
2104 }
2105 else {
2106 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002107 }
2108# elif defined(M68K)
2109 if (check_errno && is_negated_errno(d0)) {
2110 tcp->u_rval = -1;
2111 u_error = -d0;
2112 }
2113 else {
2114 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002115 }
2116# elif defined(ARM)
2117 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2118 tcp->u_rval = -1;
2119 u_error = -regs.ARM_r0;
2120 }
2121 else {
2122 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002123 }
2124# elif defined(AVR32)
2125 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2126 tcp->u_rval = -1;
2127 u_error = -regs.r12;
2128 }
2129 else {
2130 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002131 }
2132# elif defined(BFIN)
2133 if (check_errno && is_negated_errno(r0)) {
2134 tcp->u_rval = -1;
2135 u_error = -r0;
2136 } else {
2137 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002138 }
2139# elif defined(ALPHA)
2140 if (check_errno && a3) {
2141 tcp->u_rval = -1;
2142 u_error = r0;
2143 }
2144 else {
2145 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002146 }
2147# elif defined(SPARC)
2148 if (check_errno && regs.psr & PSR_C) {
2149 tcp->u_rval = -1;
2150 u_error = regs.u_regs[U_REG_O0];
2151 }
2152 else {
2153 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002154 }
2155# elif defined(SPARC64)
2156 if (check_errno && regs.tstate & 0x1100000000UL) {
2157 tcp->u_rval = -1;
2158 u_error = regs.u_regs[U_REG_O0];
2159 }
2160 else {
2161 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002162 }
2163# elif defined(HPPA)
2164 if (check_errno && is_negated_errno(r28)) {
2165 tcp->u_rval = -1;
2166 u_error = -r28;
2167 }
2168 else {
2169 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002170 }
2171# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002172 if (check_errno && is_negated_errno(r0)) {
2173 tcp->u_rval = -1;
2174 u_error = -r0;
2175 }
2176 else {
2177 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002178 }
2179# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002180 if (check_errno && is_negated_errno(r9)) {
2181 tcp->u_rval = -1;
2182 u_error = -r9;
2183 }
2184 else {
2185 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002186 }
2187# elif defined(CRISV10) || defined(CRISV32)
2188 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2189 tcp->u_rval = -1;
2190 u_error = -r10;
2191 }
2192 else {
2193 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002194 }
2195# elif defined(TILE)
2196 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002197 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2198 return -1;
2199 if (check_errno && rval < 0 && rval > -nerrnos) {
2200 tcp->u_rval = -1;
2201 u_error = -rval;
2202 }
2203 else {
2204 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002205 }
2206# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002207 if (check_errno && is_negated_errno(r3)) {
2208 tcp->u_rval = -1;
2209 u_error = -r3;
2210 }
2211 else {
2212 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002213 }
2214# endif
2215#endif /* LINUX */
2216#ifdef SUNOS4
2217 /* get error code from user struct */
2218 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2219 return -1;
2220 u_error >>= 24; /* u_error is a char */
2221
2222 /* get system call return value */
2223 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2224 return -1;
2225#endif /* SUNOS4 */
2226#ifdef SVR4
2227# ifdef SPARC
2228 /* Judicious guessing goes a long way. */
2229 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2230 tcp->u_rval = -1;
2231 u_error = tcp->status.pr_reg[R_O0];
2232 }
2233 else {
2234 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002235 }
2236# endif /* SPARC */
2237# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002238 if (tcp->status.PR_REG[EFL] & 0x1) {
2239 tcp->u_rval = -1;
2240 u_error = tcp->status.PR_REG[EAX];
2241 }
2242 else {
2243 tcp->u_rval = tcp->status.PR_REG[EAX];
2244# ifdef HAVE_LONG_LONG
2245 tcp->u_lrval =
2246 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2247 tcp->status.PR_REG[EAX];
2248# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002249 }
2250# endif /* I386 */
2251# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002252 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2253 tcp->u_rval = -1;
2254 u_error = tcp->status.PR_REG[RAX];
2255 }
2256 else {
2257 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002258 }
2259# endif /* X86_64 */
2260# ifdef MIPS
2261 if (tcp->status.pr_reg[CTX_A3]) {
2262 tcp->u_rval = -1;
2263 u_error = tcp->status.pr_reg[CTX_V0];
2264 }
2265 else {
2266 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002267 }
2268# endif /* MIPS */
2269#endif /* SVR4 */
2270#ifdef FREEBSD
2271 if (regs.r_eflags & PSL_C) {
2272 tcp->u_rval = -1;
2273 u_error = regs.r_eax;
2274 } else {
2275 tcp->u_rval = regs.r_eax;
2276 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002277 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002278 }
2279#endif /* FREEBSD */
2280 tcp->u_error = u_error;
2281 return 1;
2282}
2283
2284static void
2285dumpio(struct tcb *tcp)
2286{
2287 if (syserror(tcp))
2288 return;
2289 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2290 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002291 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002292 return;
2293 if (sysent[tcp->scno].sys_func == printargs)
2294 return;
2295 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2296 if (sysent[tcp->scno].sys_func == sys_read ||
2297 sysent[tcp->scno].sys_func == sys_pread ||
2298 sysent[tcp->scno].sys_func == sys_pread64 ||
2299 sysent[tcp->scno].sys_func == sys_recv ||
2300 sysent[tcp->scno].sys_func == sys_recvfrom)
2301 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2302 else if (sysent[tcp->scno].sys_func == sys_readv)
2303 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2304 return;
2305 }
2306 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2307 if (sysent[tcp->scno].sys_func == sys_write ||
2308 sysent[tcp->scno].sys_func == sys_pwrite ||
2309 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2310 sysent[tcp->scno].sys_func == sys_send ||
2311 sysent[tcp->scno].sys_func == sys_sendto)
2312 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2313 else if (sysent[tcp->scno].sys_func == sys_writev)
2314 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2315 return;
2316 }
2317}
2318
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002319static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002320trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321{
2322 int sys_res;
2323 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002324 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002325 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002326
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002327 /* Measure the exit time as early as possible to avoid errors. */
2328 if (dtime || cflag)
2329 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002330
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002331 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002332 if (res == 0)
2333 return res;
2334 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002335 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002336 if (res == 0)
2337 return res;
2338 if (res == 1)
2339 res = get_error(tcp);
2340 if (res == 0)
2341 return res;
2342 if (res == 1)
2343 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002344
Grant Edwards8a082772011-04-07 20:25:40 +00002345 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002346 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002347 }
2348
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002349 if (tcp->flags & TCB_REPRINT) {
2350 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002351 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002352 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002353 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002354 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002355 }
2356
2357 if (cflag) {
2358 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002359 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002360 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002361 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002362 }
2363 }
2364
2365 if (res != 1) {
2366 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002367 tabto();
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002368 tprintf("= ? <unavailable>");
2369 printtrailer();
2370 tcp->flags &= ~TCB_INSYSCALL;
2371 return res;
2372 }
2373
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002374 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002375 || (qual_flags[tcp->scno] & QUAL_RAW))
2376 sys_res = printargs(tcp);
2377 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002378 /* FIXME: not_failing_only (IOW, option -z) is broken:
2379 * failure of syscall is known only after syscall return.
2380 * Thus we end up with something like this on, say, ENOENT:
2381 * open("doesnt_exist", O_RDONLY <unfinished ...>
2382 * {next syscall decode}
2383 * whereas the intended result is that open(...) line
2384 * is not shown at all.
2385 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002386 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002387 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002388 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2389 }
2390
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002391 tprintf(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002392 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002393 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002394 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002395 qual_flags[tcp->scno] & QUAL_RAW) {
2396 if (u_error)
2397 tprintf("= -1 (errno %ld)", u_error);
2398 else
2399 tprintf("= %#lx", tcp->u_rval);
2400 }
2401 else if (!(sys_res & RVAL_NONE) && u_error) {
2402 switch (u_error) {
2403#ifdef LINUX
2404 case ERESTARTSYS:
2405 tprintf("= ? ERESTARTSYS (To be restarted)");
2406 break;
2407 case ERESTARTNOINTR:
2408 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2409 break;
2410 case ERESTARTNOHAND:
2411 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2412 break;
2413 case ERESTART_RESTARTBLOCK:
2414 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2415 break;
2416#endif /* LINUX */
2417 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002418 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002419 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002420 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002421 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002422 strerror(u_error));
2423 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002424 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002425 strerror(u_error));
2426 break;
2427 }
2428 if ((sys_res & RVAL_STR) && tcp->auxstr)
2429 tprintf(" (%s)", tcp->auxstr);
2430 }
2431 else {
2432 if (sys_res & RVAL_NONE)
2433 tprintf("= ?");
2434 else {
2435 switch (sys_res & RVAL_MASK) {
2436 case RVAL_HEX:
2437 tprintf("= %#lx", tcp->u_rval);
2438 break;
2439 case RVAL_OCTAL:
2440 tprintf("= %#lo", tcp->u_rval);
2441 break;
2442 case RVAL_UDECIMAL:
2443 tprintf("= %lu", tcp->u_rval);
2444 break;
2445 case RVAL_DECIMAL:
2446 tprintf("= %ld", tcp->u_rval);
2447 break;
2448#ifdef HAVE_LONG_LONG
2449 case RVAL_LHEX:
2450 tprintf("= %#llx", tcp->u_lrval);
2451 break;
2452 case RVAL_LOCTAL:
2453 tprintf("= %#llo", tcp->u_lrval);
2454 break;
2455 case RVAL_LUDECIMAL:
2456 tprintf("= %llu", tcp->u_lrval);
2457 break;
2458 case RVAL_LDECIMAL:
2459 tprintf("= %lld", tcp->u_lrval);
2460 break;
2461#endif
2462 default:
2463 fprintf(stderr,
2464 "invalid rval format\n");
2465 break;
2466 }
2467 }
2468 if ((sys_res & RVAL_STR) && tcp->auxstr)
2469 tprintf(" (%s)", tcp->auxstr);
2470 }
2471 if (dtime) {
2472 tv_sub(&tv, &tv, &tcp->etime);
2473 tprintf(" <%ld.%06ld>",
2474 (long) tv.tv_sec, (long) tv.tv_usec);
2475 }
2476 printtrailer();
2477
2478 dumpio(tcp);
2479 if (fflush(tcp->outf) == EOF)
2480 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002481 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002482 tcp->flags &= ~TCB_INSYSCALL;
2483 return 0;
2484}
2485
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002486int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002487trace_syscall(struct tcb *tcp)
2488{
2489 return exiting(tcp) ?
2490 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2491}