blob: 2e5053a4f600facca94914622e969e11139b7c58 [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#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000200set_personality(personality)
201int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000202{
203 switch (personality) {
204 case 0:
205 errnoent = errnoent0;
206 nerrnos = nerrnos0;
207 sysent = sysent0;
208 nsyscalls = nsyscalls0;
209 ioctlent = ioctlent0;
210 nioctlents = nioctlents0;
211 signalent = signalent0;
212 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000213 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214 break;
215
216#if SUPPORTED_PERSONALITIES >= 2
217 case 1:
218 errnoent = errnoent1;
219 nerrnos = nerrnos1;
220 sysent = sysent1;
221 nsyscalls = nsyscalls1;
222 ioctlent = ioctlent1;
223 nioctlents = nioctlents1;
224 signalent = signalent1;
225 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000226 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227 break;
228#endif /* SUPPORTED_PERSONALITIES >= 2 */
229
230#if SUPPORTED_PERSONALITIES >= 3
231 case 2:
232 errnoent = errnoent2;
233 nerrnos = nerrnos2;
234 sysent = sysent2;
235 nsyscalls = nsyscalls2;
236 ioctlent = ioctlent2;
237 nioctlents = nioctlents2;
238 signalent = signalent2;
239 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000240 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241 break;
242#endif /* SUPPORTED_PERSONALITIES >= 3 */
243
244 default:
245 return -1;
246 }
247
248 current_personality = personality;
249 return 0;
250}
251
Roland McGrathe10e62a2004-09-04 04:20:43 +0000252
253struct call_counts {
254 struct timeval time;
255 int calls, errors;
256};
257
258static struct call_counts *counts;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000259
260static struct timeval shortest = { 1000000, 0 };
261
Roland McGrath9797ceb2002-12-30 10:23:00 +0000262static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000263
Roland McGrathe10e62a2004-09-04 04:20:43 +0000264static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265 int bitflag;
266 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000267 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000268 char *argument_name;
269} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000270 { QUAL_TRACE, "trace", qual_syscall, "system call" },
271 { QUAL_TRACE, "t", qual_syscall, "system call" },
272 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
273 { QUAL_ABBREV, "a", qual_syscall, "system call" },
274 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
275 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
276 { QUAL_RAW, "raw", qual_syscall, "system call" },
277 { QUAL_RAW, "x", qual_syscall, "system call" },
278 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
279 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
280 { QUAL_SIGNAL, "s", qual_signal, "signal" },
281 { QUAL_FAULT, "fault", qual_fault, "fault" },
282 { QUAL_FAULT, "faults", qual_fault, "fault" },
283 { QUAL_FAULT, "m", qual_fault, "fault" },
284 { QUAL_READ, "read", qual_desc, "descriptor" },
285 { QUAL_READ, "reads", qual_desc, "descriptor" },
286 { QUAL_READ, "r", qual_desc, "descriptor" },
287 { QUAL_WRITE, "write", qual_desc, "descriptor" },
288 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
289 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000290 { 0, NULL, NULL, NULL },
291};
292
Roland McGrath9797ceb2002-12-30 10:23:00 +0000293static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000294qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000295 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000296 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000297 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000298 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299{
Roland McGrath138c6a32006-01-12 09:50:49 +0000300 if (pers == 0 || pers < 0) {
301 if (not)
302 qual_flags0[n] &= ~opt->bitflag;
303 else
304 qual_flags0[n] |= opt->bitflag;
305 }
306
307#if SUPPORTED_PERSONALITIES >= 2
308 if (pers == 1 || pers < 0) {
309 if (not)
310 qual_flags1[n] &= ~opt->bitflag;
311 else
312 qual_flags1[n] |= opt->bitflag;
313 }
314#endif /* SUPPORTED_PERSONALITIES >= 2 */
315
316#if SUPPORTED_PERSONALITIES >= 3
317 if (pers == 2 || pers < 0) {
318 if (not)
319 qual_flags2[n] &= ~opt->bitflag;
320 else
321 qual_flags2[n] |= opt->bitflag;
322 }
323#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000324}
325
326static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000327qual_syscall(s, opt, not)
328 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000329 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000330 int not;
331{
332 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000333 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000334
Roland McGrath48a035f2006-01-12 09:45:56 +0000335 if (isdigit((unsigned char)*s)) {
336 int i = atoi(s);
337 if (i < 0 || i >= nsyscalls)
338 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000339 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000340 return 0;
341 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000342 for (i = 0; i < nsyscalls; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000343 if (strcmp(s, sysent0[i].sys_name) == 0) {
344 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000345 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000346 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000347
348#if SUPPORTED_PERSONALITIES >= 2
349 if (strcmp(s, sysent1[i].sys_name) == 0) {
350 qualify_one(i, opt, not, 1);
351 rc = 0;
352 }
353#endif /* SUPPORTED_PERSONALITIES >= 2 */
354
355#if SUPPORTED_PERSONALITIES >= 3
356 if (strcmp(s, sysent2[i].sys_name) == 0) {
357 qualify_one(i, opt, not, 2);
358 rc = 0;
359 }
360#endif /* SUPPORTED_PERSONALITIES >= 3 */
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000362 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000363}
364
365static int
366qual_signal(s, opt, not)
367 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000368 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000369 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000370{
371 int i;
372 char buf[32];
373
Roland McGrath48a035f2006-01-12 09:45:56 +0000374 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000375 int signo = atoi(s);
376 if (signo < 0 || signo >= MAX_QUALS)
377 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000378 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000379 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000380 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000381 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000382 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383 strcpy(buf, s);
384 s = buf;
385 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000386 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387 if (strncmp(s, "SIG", 3) == 0)
388 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000389 for (i = 0; i <= NSIG; i++)
390 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000391 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000392 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 }
Roland McGrath76421df2005-02-02 03:51:18 +0000394 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000395}
396
397static int
398qual_fault(s, opt, not)
399 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000400 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000401 int not;
402{
403 return -1;
404}
405
406static int
407qual_desc(s, opt, not)
408 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000409 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000410 int not;
411{
Roland McGrath48a035f2006-01-12 09:45:56 +0000412 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000413 int desc = atoi(s);
414 if (desc < 0 || desc >= MAX_QUALS)
415 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000416 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000417 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418 }
419 return -1;
420}
421
422static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000424 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000425{
426 if (strcmp(s, "file") == 0)
427 return TRACE_FILE;
428 if (strcmp(s, "ipc") == 0)
429 return TRACE_IPC;
430 if (strcmp(s, "network") == 0)
431 return TRACE_NETWORK;
432 if (strcmp(s, "process") == 0)
433 return TRACE_PROCESS;
434 if (strcmp(s, "signal") == 0)
435 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000436 if (strcmp(s, "desc") == 0)
437 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 return -1;
439}
440
441void
442qualify(s)
443char *s;
444{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000445 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 int not;
447 char *p;
448 int i, n;
449
450 opt = &qual_options[0];
451 for (i = 0; (p = qual_options[i].option_name); i++) {
452 n = strlen(p);
453 if (strncmp(s, p, n) == 0 && s[n] == '=') {
454 opt = &qual_options[i];
455 s += n + 1;
456 break;
457 }
458 }
459 not = 0;
460 if (*s == '!') {
461 not = 1;
462 s++;
463 }
464 if (strcmp(s, "none") == 0) {
465 not = 1 - not;
466 s = "all";
467 }
468 if (strcmp(s, "all") == 0) {
469 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000470 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471 }
472 return;
473 }
474 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000475 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000476 }
477 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
478 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
479 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000480 if (sysent0[i].sys_flags & n)
481 qualify_one(i, opt, not, 0);
482
483#if SUPPORTED_PERSONALITIES >= 2
484 if (sysent1[i].sys_flags & n)
485 qualify_one(i, opt, not, 1);
486#endif /* SUPPORTED_PERSONALITIES >= 2 */
487
488#if SUPPORTED_PERSONALITIES >= 3
489 if (sysent2[i].sys_flags & n)
490 qualify_one(i, opt, not, 2);
491#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 }
493 continue;
494 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000495 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496 fprintf(stderr, "strace: invalid %s `%s'\n",
497 opt->argument_name, p);
498 exit(1);
499 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500 }
501 return;
502}
503
504static void
505dumpio(tcp)
506struct tcb *tcp;
507{
508 if (syserror(tcp))
509 return;
510 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
511 return;
Roland McGrath17352792005-06-07 23:21:26 +0000512 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000514#ifdef SYS_pread64
515 case SYS_pread64:
516#endif
517#if defined SYS_pread && SYS_pread64 != SYS_pread
518 case SYS_pread:
519#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520#ifdef SYS_recv
521 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000522#elif defined SYS_sub_recv
523 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524#endif
525#ifdef SYS_recvfrom
526 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000527#elif defined SYS_sub_recvfrom
528 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529#endif
530 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
531 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
532 break;
533 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000534#ifdef SYS_pwrite64
535 case SYS_pwrite64:
536#endif
537#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
538 case SYS_pwrite:
539#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540#ifdef SYS_send
541 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000542#elif defined SYS_sub_send
543 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544#endif
545#ifdef SYS_sendto
546 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000547#elif defined SYS_sub_sendto
548 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549#endif
550 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
551 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
552 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000553#ifdef SYS_readv
554 case SYS_readv:
555 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
556 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
557 break;
558#endif
559#ifdef SYS_writev
560 case SYS_writev:
561
562 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
563 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
564 break;
565#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566 }
567}
568
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000569#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000570enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000571#else /* FREEBSD */
572enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
573
574struct subcall {
575 int call;
576 int nsubcalls;
577 int subcalls[5];
578};
579
Roland McGratha4d48532005-06-08 20:45:28 +0000580static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000582#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000583 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000584#else
585 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
586#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000587 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
588};
589#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000590
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000591#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592
Roland McGratha4d48532005-06-08 20:45:28 +0000593static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 /* SYS_SOCKET */ 97,
595 /* SYS_BIND */ 104,
596 /* SYS_CONNECT */ 98,
597 /* SYS_LISTEN */ 106,
598 /* SYS_ACCEPT */ 99,
599 /* SYS_GETSOCKNAME */ 150,
600 /* SYS_GETPEERNAME */ 141,
601 /* SYS_SOCKETPAIR */ 135,
602 /* SYS_SEND */ 101,
603 /* SYS_RECV */ 102,
604 /* SYS_SENDTO */ 133,
605 /* SYS_RECVFROM */ 125,
606 /* SYS_SHUTDOWN */ 134,
607 /* SYS_SETSOCKOPT */ 105,
608 /* SYS_GETSOCKOPT */ 118,
609 /* SYS_SENDMSG */ 114,
610 /* SYS_RECVMSG */ 113
611};
612
Roland McGratha4d48532005-06-08 20:45:28 +0000613#if defined (SPARC) || defined (SPARC64)
614static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000615sparc_socket_decode (tcp)
616struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617{
618 volatile long addr;
619 volatile int i, n;
620
621 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
622 return;
623 }
624 tcp->scno = socket_map [tcp->u_arg [0]-1];
625 n = tcp->u_nargs = sysent [tcp->scno].nargs;
626 addr = tcp->u_arg [1];
627 for (i = 0; i < n; i++){
628 int arg;
629 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
630 arg = 0;
631 tcp->u_arg [i] = arg;
632 addr += sizeof (arg);
633 }
634}
Roland McGratha4d48532005-06-08 20:45:28 +0000635#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636
Roland McGratha4d48532005-06-08 20:45:28 +0000637static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638decode_subcall(tcp, subcall, nsubcalls, style)
639struct tcb *tcp;
640int subcall;
641int nsubcalls;
642enum subcall_style style;
643{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000644 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000645 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000646 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000647
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 switch (style) {
649 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000650 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
651 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652 tcp->scno = subcall + tcp->u_arg[0];
653 if (sysent[tcp->scno].nargs != -1)
654 tcp->u_nargs = sysent[tcp->scno].nargs;
655 else
656 tcp->u_nargs--;
657 for (i = 0; i < tcp->u_nargs; i++)
658 tcp->u_arg[i] = tcp->u_arg[i + 1];
659 break;
660 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000661 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
662 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000663 tcp->scno = subcall + tcp->u_arg[0];
664 addr = tcp->u_arg[1];
665 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000666 if (size == sizeof(int)) {
667 unsigned int arg;
668 if (umove(tcp, addr, &arg) < 0)
669 arg = 0;
670 tcp->u_arg[i] = arg;
671 }
672 else if (size == sizeof(long)) {
673 unsigned long arg;
674 if (umove(tcp, addr, &arg) < 0)
675 arg = 0;
676 tcp->u_arg[i] = arg;
677 }
678 else
679 abort();
680 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681 }
682 tcp->u_nargs = sysent[tcp->scno].nargs;
683 break;
684 case mask_style:
685 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000686 for (i = 0; mask; i++)
687 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000688 if (i >= nsubcalls)
689 return;
690 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000691 tcp->scno = subcall + i;
692 if (sysent[tcp->scno].nargs != -1)
693 tcp->u_nargs = sysent[tcp->scno].nargs;
694 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000695 case door_style:
696 /*
697 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000698 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000699 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000700 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
701 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000702 tcp->scno = subcall + tcp->u_arg[5];
703 if (sysent[tcp->scno].nargs != -1)
704 tcp->u_nargs = sysent[tcp->scno].nargs;
705 else
706 tcp->u_nargs--;
707 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000708#ifdef FREEBSD
709 case table_style:
710 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
711 if (subcalls_table[i].call == tcp->scno) break;
712 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
713 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
714 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
715 for (i = 0; i < tcp->u_nargs; i++)
716 tcp->u_arg[i] = tcp->u_arg[i + 1];
717 }
718 break;
719#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720 }
721}
722#endif
723
724struct tcb *tcp_last = NULL;
725
726static int
727internal_syscall(tcp)
728struct tcb *tcp;
729{
730 /*
731 * We must always trace a few critical system calls in order to
732 * correctly support following forks in the presence of tracing
733 * qualifiers.
734 */
Roland McGrath17352792005-06-07 23:21:26 +0000735 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000736#ifdef SYS_fork
737 case SYS_fork:
738#endif
739#ifdef SYS_vfork
740 case SYS_vfork:
741#endif
John Hughes4e36a812001-04-18 15:11:51 +0000742#ifdef SYS_fork1
743 case SYS_fork1:
744#endif
745#ifdef SYS_forkall
746 case SYS_forkall:
747#endif
748#ifdef SYS_rfork1
749 case SYS_rfork1:
750#endif
751#ifdef SYS_rforkall
752 case SYS_rforkall:
753#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000754#ifdef SYS_rfork
755 case SYS_rfork:
756#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 internal_fork(tcp);
758 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000759#ifdef SYS_clone
760 case SYS_clone:
761 internal_clone(tcp);
762 break;
763#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000764#ifdef SYS_clone2
765 case SYS_clone2:
766 internal_clone(tcp);
767 break;
768#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769#ifdef SYS_execv
770 case SYS_execv:
771#endif
772#ifdef SYS_execve
773 case SYS_execve:
774#endif
John Hughes4e36a812001-04-18 15:11:51 +0000775#ifdef SYS_rexecve
776 case SYS_rexecve:
777#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 internal_exec(tcp);
779 break;
780
781#ifdef SYS_wait
782 case SYS_wait:
783#endif
784#ifdef SYS_wait4
785 case SYS_wait4:
786#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000787#ifdef SYS32_wait4
788 case SYS32_wait4:
789#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790#ifdef SYS_waitpid
791 case SYS_waitpid:
792#endif
793#ifdef SYS_waitsys
794 case SYS_waitsys:
795#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000796 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000798#ifdef SYS_waitid
799 case SYS_waitid:
800 internal_wait(tcp, 3);
801 break;
802#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803
804#ifdef SYS_exit
805 case SYS_exit:
806#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000807#ifdef SYS32_exit
808 case SYS32_exit:
809#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000810#ifdef __NR_exit_group
811 case __NR_exit_group:
812#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000813#ifdef IA64
814 case 252: /* IA-32 __NR_exit_group */
815#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 internal_exit(tcp);
817 break;
818 }
819 return 0;
820}
821
Wichert Akkermanc7926982000-04-10 22:22:31 +0000822
823#ifdef LINUX
824#if defined (I386)
825 static long eax;
826#elif defined (IA64)
827 long r8, r10, psr;
828 long ia32 = 0;
829#elif defined (POWERPC)
830 static long result,flags;
831#elif defined (M68K)
832 static int d0;
833#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000834 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000835#elif defined (ALPHA)
836 static long r0;
837 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000838#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000839 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000840 static unsigned long trap;
841#elif defined(MIPS)
842 static long a3;
843 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000844#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000845 static long gpr2;
846 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000848#elif defined(HPPA)
849 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000850#elif defined(SH)
851 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000852#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000853 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000854#elif defined(X86_64)
855 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000856#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000857#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000858#ifdef FREEBSD
859 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000860#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000861
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000863get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864struct tcb *tcp;
865{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000867#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000869#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000870
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000871#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000872#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000873 if (tcp->flags & TCB_WAITEXECVE) {
874 /*
875 * When the execve system call completes successfully, the
876 * new process still has -ENOSYS (old style) or __NR_execve
877 * (new style) in gpr2. We cannot recover the scno again
878 * by disassembly, because the image that executed the
879 * syscall is gone now. Fortunately, we don't want it. We
880 * leave the flag set so that syscall_fixup can fake the
881 * result.
882 */
883 if (tcp->flags & TCB_INSYSCALL)
884 return 1;
885 /*
886 * This is the SIGTRAP after execve. We cannot try to read
887 * the system call here either.
888 */
889 tcp->flags &= ~TCB_WAITEXECVE;
890 return 0;
891 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000892
893 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
894 return -1;
895
896 if (syscall_mode != -ENOSYS) {
897 /*
898 * Since kernel version 2.5.44 the scno gets passed in gpr2.
899 */
900 scno = syscall_mode;
901 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000902 /*
903 * Old style of "passing" the scno via the SVC instruction.
904 */
905
906 long opcode, offset_reg, tmp;
907 void * svc_addr;
908 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
909 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
910 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
911 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000912
Michal Ludvig882eda82002-11-11 12:50:47 +0000913 if (upeek(pid, PT_PSWADDR, &pc) < 0)
914 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000915 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000916 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000917 if (errno) {
918 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000919 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000920 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000921
922 /*
923 * We have to check if the SVC got executed directly or via an
924 * EXECUTE instruction. In case of EXECUTE it is necessary to do
925 * instruction decoding to derive the system call number.
926 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
927 * so that this doesn't work if a SVC opcode is part of an EXECUTE
928 * opcode. Since there is no way to find out the opcode size this
929 * is the best we can do...
930 */
931
932 if ((opcode & 0xff00) == 0x0a00) {
933 /* SVC opcode */
934 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000935 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000936 else {
937 /* SVC got executed by EXECUTE instruction */
938
939 /*
940 * Do instruction decoding of EXECUTE. If you really want to
941 * understand this, read the Principles of Operations.
942 */
943 svc_addr = (void *) (opcode & 0xfff);
944
945 tmp = 0;
946 offset_reg = (opcode & 0x000f0000) >> 16;
947 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
948 return -1;
949 svc_addr += tmp;
950
951 tmp = 0;
952 offset_reg = (opcode & 0x0000f000) >> 12;
953 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
954 return -1;
955 svc_addr += tmp;
956
957 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
958 if (errno)
959 return -1;
960#if defined(S390X)
961 scno >>= 48;
962#else
963 scno >>= 16;
964#endif
965 tmp = 0;
966 offset_reg = (opcode & 0x00f00000) >> 20;
967 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
968 return -1;
969
970 scno = (scno | tmp) & 0xff;
971 }
972 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000973#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000974 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 return -1;
976 if (!(tcp->flags & TCB_INSYSCALL)) {
977 /* Check if we return from execve. */
978 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
979 tcp->flags &= ~TCB_WAITEXECVE;
980 return 0;
981 }
982 }
983#elif defined (I386)
984 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
985 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000986#elif defined (X86_64)
987 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
988 return -1;
989
Roland McGrath761b5d72002-12-15 23:58:31 +0000990 if (!(tcp->flags & TCB_INSYSCALL)) {
991 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000992 long val;
993
994 /* Check CS register value. On x86-64 linux it is:
995 * 0x33 for long mode (64 bit)
996 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000997 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000998 * to be cached.
999 */
1000 if (upeek(pid, 8*CS, &val) < 0)
1001 return -1;
1002 switch(val)
1003 {
1004 case 0x23: currpers = 1; break;
1005 case 0x33: currpers = 0; break;
1006 default:
1007 fprintf(stderr, "Unknown value CS=0x%02X while "
1008 "detecting personality of process "
1009 "PID=%d\n", (int)val, pid);
1010 currpers = current_personality;
1011 break;
1012 }
1013#if 0
1014 /* This version analyzes the opcode of a syscall instruction.
1015 * (int 0x80 on i386 vs. syscall on x86-64)
1016 * It works, but is too complicated.
1017 */
1018 unsigned long val, rip, i;
1019
1020 if(upeek(pid, 8*RIP, &rip)<0)
1021 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +00001022
Michal Ludvig0e035502002-09-23 15:41:01 +00001023 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
1024 rip-=2;
1025 errno = 0;
1026
Roland McGrath761b5d72002-12-15 23:58:31 +00001027 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
1028 if (errno)
1029 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +00001030 strerror(errno));
1031 switch (call & 0xffff)
1032 {
1033 /* x86-64: syscall = 0x0f 0x05 */
1034 case 0x050f: currpers = 0; break;
1035 /* i386: int 0x80 = 0xcd 0x80 */
1036 case 0x80cd: currpers = 1; break;
1037 default:
1038 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +00001039 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +00001040 "Unknown syscall opcode (0x%04X) while "
1041 "detecting personality of process "
1042 "PID=%d\n", (int)call, pid);
1043 break;
1044 }
1045#endif
1046 if(currpers != current_personality)
1047 {
1048 char *names[]={"64 bit", "32 bit"};
1049 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +00001050 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +00001051 pid, names[current_personality]);
1052 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001053 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001054#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001055# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001056 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001057 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001058 if (!(tcp->flags & TCB_INSYSCALL)) {
1059 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001060 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001061 return -1;
1062 } else {
1063 if (upeek (pid, PT_R15, &scno) < 0)
1064 return -1;
1065 }
Roland McGrathba954762003-03-05 06:29:06 +00001066 /* Check if we return from execve. */
1067 if (tcp->flags & TCB_WAITEXECVE) {
1068 tcp->flags &= ~TCB_WAITEXECVE;
1069 return 0;
1070 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001071 } else {
1072 /* syscall in progress */
1073 if (upeek (pid, PT_R8, &r8) < 0)
1074 return -1;
1075 if (upeek (pid, PT_R10, &r10) < 0)
1076 return -1;
1077 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001079 /*
1080 * Read complete register set in one go.
1081 */
1082 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1083 return -1;
1084
1085 /*
1086 * We only need to grab the syscall number on syscall entry.
1087 */
1088 if (regs.ARM_ip == 0) {
1089 /*
1090 * Note: we only deal with only 32-bit CPUs here.
1091 */
1092 if (regs.ARM_cpsr & 0x20) {
1093 /*
1094 * Get the Thumb-mode system call number
1095 */
1096 scno = regs.ARM_r7;
1097 } else {
1098 /*
1099 * Get the ARM-mode system call number
1100 */
1101 errno = 0;
1102 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1103 if (errno)
1104 return -1;
1105
1106 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1107 tcp->flags &= ~TCB_WAITEXECVE;
1108 return 0;
1109 }
1110
Roland McGrathf691bd22006-04-25 07:34:41 +00001111 /* Handle the EABI syscall convention. We do not
1112 bother converting structures between the two
1113 ABIs, but basic functionality should work even
1114 if strace and the traced program have different
1115 ABIs. */
1116 if (scno == 0xef000000) {
1117 scno = regs.ARM_r7;
1118 } else {
1119 if ((scno & 0x0ff00000) != 0x0f900000) {
1120 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1121 scno);
1122 return -1;
1123 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001124
Roland McGrathf691bd22006-04-25 07:34:41 +00001125 /*
1126 * Fixup the syscall number
1127 */
1128 scno &= 0x000fffff;
1129 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001130 }
1131
1132 if (tcp->flags & TCB_INSYSCALL) {
1133 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1134 tcp->flags &= ~TCB_INSYSCALL;
1135 }
1136 } else {
1137 if (!(tcp->flags & TCB_INSYSCALL)) {
1138 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1139 tcp->flags |= TCB_INSYSCALL;
1140 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 }
1142#elif defined (M68K)
1143 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1144 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001145#elif defined (MIPS)
1146 if (upeek(pid, REG_A3, &a3) < 0)
1147 return -1;
1148
1149 if(!(tcp->flags & TCB_INSYSCALL)) {
1150 if (upeek(pid, REG_V0, &scno) < 0)
1151 return -1;
1152
1153 if (scno < 0 || scno > nsyscalls) {
1154 if(a3 == 0 || a3 == -1) {
1155 if(debug)
1156 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1157 return 0;
1158 }
1159 }
1160 } else {
1161 if (upeek(pid, REG_V0, &r2) < 0)
1162 return -1;
1163 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164#elif defined (ALPHA)
1165 if (upeek(pid, REG_A3, &a3) < 0)
1166 return -1;
1167
1168 if (!(tcp->flags & TCB_INSYSCALL)) {
1169 if (upeek(pid, REG_R0, &scno) < 0)
1170 return -1;
1171
1172 /* Check if we return from execve. */
1173 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1174 tcp->flags &= ~TCB_WAITEXECVE;
1175 return 0;
1176 }
1177
1178 /*
1179 * Do some sanity checks to figure out if it's
1180 * really a syscall entry
1181 */
1182 if (scno < 0 || scno > nsyscalls) {
1183 if (a3 == 0 || a3 == -1) {
1184 if (debug)
1185 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1186 return 0;
1187 }
1188 }
1189 }
1190 else {
1191 if (upeek(pid, REG_R0, &r0) < 0)
1192 return -1;
1193 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001194#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 /* Everything we need is in the current register set. */
1196 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1197 return -1;
1198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199 /* If we are entering, then disassemble the syscall trap. */
1200 if (!(tcp->flags & TCB_INSYSCALL)) {
1201 /* Retrieve the syscall trap instruction. */
1202 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001203 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001204#if defined(SPARC64)
1205 trap >>= 32;
1206#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207 if (errno)
1208 return -1;
1209
1210 /* Disassemble the trap to see what personality to use. */
1211 switch (trap) {
1212 case 0x91d02010:
1213 /* Linux/SPARC syscall trap. */
1214 set_personality(0);
1215 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001216 case 0x91d0206d:
1217 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001218 set_personality(2);
1219 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220 case 0x91d02000:
1221 /* SunOS syscall trap. (pers 1) */
1222 fprintf(stderr,"syscall: SunOS no support\n");
1223 return -1;
1224 case 0x91d02008:
1225 /* Solaris 2.x syscall trap. (per 2) */
1226 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001227 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228 case 0x91d02009:
1229 /* NetBSD/FreeBSD syscall trap. */
1230 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1231 return -1;
1232 case 0x91d02027:
1233 /* Solaris 2.x gettimeofday */
1234 set_personality(1);
1235 break;
1236 default:
1237 /* Unknown syscall trap. */
1238 if(tcp->flags & TCB_WAITEXECVE) {
1239 tcp->flags &= ~TCB_WAITEXECVE;
1240 return 0;
1241 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001242#if defined (SPARC64)
1243 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1244#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001245 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001246#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247 return -1;
1248 }
1249
1250 /* Extract the system call number from the registers. */
1251 if (trap == 0x91d02027)
1252 scno = 156;
1253 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001254 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001256 scno = regs.r_o0;
1257 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001258 }
1259 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001260#elif defined(HPPA)
1261 if (upeek(pid, PT_GR20, &scno) < 0)
1262 return -1;
1263 if (!(tcp->flags & TCB_INSYSCALL)) {
1264 /* Check if we return from execve. */
1265 if ((tcp->flags & TCB_WAITEXECVE)) {
1266 tcp->flags &= ~TCB_WAITEXECVE;
1267 return 0;
1268 }
1269 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001270#elif defined(SH)
1271 /*
1272 * In the new syscall ABI, the system call number is in R3.
1273 */
1274 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1275 return -1;
1276
1277 if (scno < 0) {
1278 /* Odd as it may seem, a glibc bug has been known to cause
1279 glibc to issue bogus negative syscall numbers. So for
1280 our purposes, make strace print what it *should* have been */
1281 long correct_scno = (scno & 0xff);
1282 if (debug)
1283 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001284 "Detected glibc bug: bogus system call number = %ld, "
1285 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001286 scno,
1287 correct_scno);
1288 scno = correct_scno;
1289 }
1290
1291
1292 if (!(tcp->flags & TCB_INSYSCALL)) {
1293 /* Check if we return from execve. */
1294 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1295 tcp->flags &= ~TCB_WAITEXECVE;
1296 return 0;
1297 }
1298 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001299#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001300 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1301 return -1;
1302 scno &= 0xFFFF;
1303
1304 if (!(tcp->flags & TCB_INSYSCALL)) {
1305 /* Check if we return from execve. */
1306 if (tcp->flags & TCB_WAITEXECVE) {
1307 tcp->flags &= ~TCB_WAITEXECVE;
1308 return 0;
1309 }
1310 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001311#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312#endif /* LINUX */
1313#ifdef SUNOS4
1314 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1315 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001316#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001317 /* new syscall ABI returns result in R0 */
1318 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1319 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001320#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001321 /* ABI defines result returned in r9 */
1322 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1323 return -1;
1324
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001325#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001328 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001330#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001331 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001332#else /* FREEBSD */
1333 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1334 perror("pread");
1335 return -1;
1336 }
1337 switch (regs.r_eax) {
1338 case SYS_syscall:
1339 case SYS___syscall:
1340 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1341 break;
1342 default:
1343 scno = regs.r_eax;
1344 break;
1345 }
1346#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001348#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001349 if (!(tcp->flags & TCB_INSYSCALL))
1350 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001351 return 1;
1352}
1353
Pavel Machek4dc3b142000-02-01 17:58:41 +00001354
Roland McGrath17352792005-06-07 23:21:26 +00001355long
1356known_scno(tcp)
1357struct tcb *tcp;
1358{
1359 long scno = tcp->scno;
1360 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1361 scno = sysent[scno].native_scno;
1362 else
1363 scno += NR_SYSCALL_BASE;
1364 return scno;
1365}
1366
Roland McGratha4d48532005-06-08 20:45:28 +00001367static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001368syscall_fixup(tcp)
1369struct tcb *tcp;
1370{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001371#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001372 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001373#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001374 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001375
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001377 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 if (
1379 scno == SYS_fork
1380#ifdef SYS_vfork
1381 || scno == SYS_vfork
1382#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001383#ifdef SYS_fork1
1384 || scno == SYS_fork1
1385#endif /* SYS_fork1 */
1386#ifdef SYS_forkall
1387 || scno == SYS_forkall
1388#endif /* SYS_forkall */
1389#ifdef SYS_rfork1
1390 || scno == SYS_rfork1
1391#endif /* SYS_fork1 */
1392#ifdef SYS_rforkall
1393 || scno == SYS_rforkall
1394#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 ) {
1396 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001397 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001398 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 }
1401 else {
1402 fprintf(stderr, "syscall: missing entry\n");
1403 tcp->flags |= TCB_INSYSCALL;
1404 }
1405 }
1406 }
1407 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001408 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 fprintf(stderr, "syscall: missing exit\n");
1410 tcp->flags &= ~TCB_INSYSCALL;
1411 }
1412 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001413#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414#ifdef SUNOS4
1415 if (!(tcp->flags & TCB_INSYSCALL)) {
1416 if (scno == 0) {
1417 fprintf(stderr, "syscall: missing entry\n");
1418 tcp->flags |= TCB_INSYSCALL;
1419 }
1420 }
1421 else {
1422 if (scno != 0) {
1423 if (debug) {
1424 /*
1425 * This happens when a signal handler
1426 * for a signal which interrupted a
1427 * a system call makes another system call.
1428 */
1429 fprintf(stderr, "syscall: missing exit\n");
1430 }
1431 tcp->flags &= ~TCB_INSYSCALL;
1432 }
1433 }
1434#endif /* SUNOS4 */
1435#ifdef LINUX
1436#if defined (I386)
1437 if (upeek(pid, 4*EAX, &eax) < 0)
1438 return -1;
1439 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1440 if (debug)
1441 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1442 return 0;
1443 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001444#elif defined (X86_64)
1445 if (upeek(pid, 8*RAX, &rax) < 0)
1446 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001447 if (current_personality == 1)
1448 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001449 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1450 if (debug)
1451 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1452 return 0;
1453 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001454#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001455 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1456 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001457 if (syscall_mode != -ENOSYS)
1458 syscall_mode = tcp->scno;
1459 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001460 if (debug)
1461 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1462 return 0;
1463 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001464 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1465 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1466 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1467 /*
1468 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1469 * flag set for the post-execve SIGTRAP to see and reset.
1470 */
1471 gpr2 = 0;
1472 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473#elif defined (POWERPC)
1474# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001475 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001477 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478 return -1;
1479 if (flags & SO_MASK)
1480 result = -result;
1481#elif defined (M68K)
1482 if (upeek(pid, 4*PT_D0, &d0) < 0)
1483 return -1;
1484 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1485 if (debug)
1486 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1487 return 0;
1488 }
1489#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001490 /*
1491 * Nothing required
1492 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001493#elif defined (HPPA)
1494 if (upeek(pid, PT_GR28, &r28) < 0)
1495 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001496#elif defined(IA64)
1497 if (upeek(pid, PT_R10, &r10) < 0)
1498 return -1;
1499 if (upeek(pid, PT_R8, &r8) < 0)
1500 return -1;
1501 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1502 if (debug)
1503 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1504 return 0;
1505 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001506#endif
1507#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001508 return 1;
1509}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510
Roland McGratha4d48532005-06-08 20:45:28 +00001511static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001512get_error(tcp)
1513struct tcb *tcp;
1514{
1515 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001517#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001518 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1519 tcp->u_rval = -1;
1520 u_error = -gpr2;
1521 }
1522 else {
1523 tcp->u_rval = gpr2;
1524 u_error = 0;
1525 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001526#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527#ifdef I386
1528 if (eax < 0 && -eax < nerrnos) {
1529 tcp->u_rval = -1;
1530 u_error = -eax;
1531 }
1532 else {
1533 tcp->u_rval = eax;
1534 u_error = 0;
1535 }
1536#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001537#ifdef X86_64
1538 if (rax < 0 && -rax < nerrnos) {
1539 tcp->u_rval = -1;
1540 u_error = -rax;
1541 }
1542 else {
1543 tcp->u_rval = rax;
1544 u_error = 0;
1545 }
1546#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001547#ifdef IA64
1548 if (ia32) {
1549 int err;
1550
1551 err = (int)r8;
1552 if (err < 0 && -err < nerrnos) {
1553 tcp->u_rval = -1;
1554 u_error = -err;
1555 }
1556 else {
1557 tcp->u_rval = err;
1558 u_error = 0;
1559 }
1560 } else {
1561 if (r10) {
1562 tcp->u_rval = -1;
1563 u_error = r8;
1564 } else {
1565 tcp->u_rval = r8;
1566 u_error = 0;
1567 }
1568 }
1569#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001570#ifdef MIPS
1571 if (a3) {
1572 tcp->u_rval = -1;
1573 u_error = r2;
1574 } else {
1575 tcp->u_rval = r2;
1576 u_error = 0;
1577 }
1578#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001580 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001581 tcp->u_rval = -1;
1582 u_error = -result;
1583 }
1584 else {
1585 tcp->u_rval = result;
1586 u_error = 0;
1587 }
1588#else /* !POWERPC */
1589#ifdef M68K
1590 if (d0 && (unsigned) -d0 < nerrnos) {
1591 tcp->u_rval = -1;
1592 u_error = -d0;
1593 }
1594 else {
1595 tcp->u_rval = d0;
1596 u_error = 0;
1597 }
1598#else /* !M68K */
1599#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001600 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001602 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 }
1604 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001605 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 u_error = 0;
1607 }
1608#else /* !ARM */
1609#ifdef ALPHA
1610 if (a3) {
1611 tcp->u_rval = -1;
1612 u_error = r0;
1613 }
1614 else {
1615 tcp->u_rval = r0;
1616 u_error = 0;
1617 }
1618#else /* !ALPHA */
1619#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001620 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001622 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 }
1624 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001625 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 u_error = 0;
1627 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001628#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001629#ifdef SPARC64
1630 if (regs.r_tstate & 0x1100000000UL) {
1631 tcp->u_rval = -1;
1632 u_error = regs.r_o0;
1633 }
1634 else {
1635 tcp->u_rval = regs.r_o0;
1636 u_error = 0;
1637 }
1638#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001639#ifdef HPPA
1640 if (r28 && (unsigned) -r28 < nerrnos) {
1641 tcp->u_rval = -1;
1642 u_error = -r28;
1643 }
1644 else {
1645 tcp->u_rval = r28;
1646 u_error = 0;
1647 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001648#else
1649#ifdef SH
1650 /* interpret R0 as return value or error number */
1651 if (r0 && (unsigned) -r0 < nerrnos) {
1652 tcp->u_rval = -1;
1653 u_error = -r0;
1654 }
1655 else {
1656 tcp->u_rval = r0;
1657 u_error = 0;
1658 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001659#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001660#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001661 /* interpret result as return value or error number */
1662 if (r9 && (unsigned) -r9 < nerrnos) {
1663 tcp->u_rval = -1;
1664 u_error = -r9;
1665 }
1666 else {
1667 tcp->u_rval = r9;
1668 u_error = 0;
1669 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001670#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001671#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001672#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001674#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#endif /* ALPHA */
1676#endif /* ARM */
1677#endif /* M68K */
1678#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001679#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001680#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001681#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001683#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684#endif /* LINUX */
1685#ifdef SUNOS4
1686 /* get error code from user struct */
1687 if (upeek(pid, uoff(u_error), &u_error) < 0)
1688 return -1;
1689 u_error >>= 24; /* u_error is a char */
1690
1691 /* get system call return value */
1692 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1693 return -1;
1694#endif /* SUNOS4 */
1695#ifdef SVR4
1696#ifdef SPARC
1697 /* Judicious guessing goes a long way. */
1698 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1699 tcp->u_rval = -1;
1700 u_error = tcp->status.pr_reg[R_O0];
1701 }
1702 else {
1703 tcp->u_rval = tcp->status.pr_reg[R_O0];
1704 u_error = 0;
1705 }
1706#endif /* SPARC */
1707#ifdef I386
1708 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001709 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001711 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 }
1713 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001715#ifdef HAVE_LONG_LONG
1716 tcp->u_lrval =
1717 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1718 tcp->status.PR_REG[EAX];
1719#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 u_error = 0;
1721 }
1722#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001723#ifdef X86_64
1724 /* Wanna know how to kill an hour single-stepping? */
1725 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1726 tcp->u_rval = -1;
1727 u_error = tcp->status.PR_REG[RAX];
1728 }
1729 else {
1730 tcp->u_rval = tcp->status.PR_REG[RAX];
1731 u_error = 0;
1732 }
1733#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734#ifdef MIPS
1735 if (tcp->status.pr_reg[CTX_A3]) {
1736 tcp->u_rval = -1;
1737 u_error = tcp->status.pr_reg[CTX_V0];
1738 }
1739 else {
1740 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1741 u_error = 0;
1742 }
1743#endif /* MIPS */
1744#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001745#ifdef FREEBSD
1746 if (regs.r_eflags & PSL_C) {
1747 tcp->u_rval = -1;
1748 u_error = regs.r_eax;
1749 } else {
1750 tcp->u_rval = regs.r_eax;
1751 tcp->u_lrval =
1752 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1753 u_error = 0;
1754 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001755#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001756 tcp->u_error = u_error;
1757 return 1;
1758}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001759
Roland McGrathb69f81b2002-12-21 23:25:18 +00001760int
1761force_result(tcp, error, rval)
1762 struct tcb *tcp;
1763 int error;
1764 long rval;
1765{
1766#ifdef LINUX
1767#if defined(S390) || defined(S390X)
1768 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001769 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1770 return -1;
1771#else /* !S390 && !S390X */
1772#ifdef I386
1773 eax = error ? -error : rval;
1774 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1775 return -1;
1776#else /* !I386 */
1777#ifdef X86_64
1778 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001779 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001780 return -1;
1781#else
1782#ifdef IA64
1783 if (ia32) {
1784 r8 = error ? -error : rval;
1785 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1786 return -1;
1787 }
1788 else {
1789 if (error) {
1790 r8 = error;
1791 r10 = -1;
1792 }
1793 else {
1794 r8 = rval;
1795 r10 = 0;
1796 }
1797 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1798 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1799 return -1;
1800 }
1801#else /* !IA64 */
1802#ifdef MIPS
1803 if (error) {
1804 r2 = error;
1805 a3 = -1;
1806 }
1807 else {
1808 r2 = rval;
1809 a3 = 0;
1810 }
1811 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1812 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1813 return -1;
1814#else
1815#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001816 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001817 return -1;
1818 if (error) {
1819 flags |= SO_MASK;
1820 result = error;
1821 }
1822 else {
1823 flags &= ~SO_MASK;
1824 result = rval;
1825 }
Roland McGratheb285352003-01-14 09:59:00 +00001826 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1827 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 return -1;
1829#else /* !POWERPC */
1830#ifdef M68K
1831 d0 = error ? -error : rval;
1832 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1833 return -1;
1834#else /* !M68K */
1835#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001836 regs.ARM_r0 = error ? -error : rval;
1837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 return -1;
1839#else /* !ARM */
1840#ifdef ALPHA
1841 if (error) {
1842 a3 = -1;
1843 r0 = error;
1844 }
1845 else {
1846 a3 = 0;
1847 r0 = rval;
1848 }
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1850 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1851 return -1;
1852#else /* !ALPHA */
1853#ifdef SPARC
1854 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1855 return -1;
1856 if (error) {
1857 regs.r_psr |= PSR_C;
1858 regs.r_o0 = error;
1859 }
1860 else {
1861 regs.r_psr &= ~PSR_C;
1862 regs.r_o0 = rval;
1863 }
1864 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1865 return -1;
1866#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001867#ifdef SPARC64
1868 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1869 return -1;
1870 if (error) {
1871 regs.r_tstate |= 0x1100000000UL;
1872 regs.r_o0 = error;
1873 }
1874 else {
1875 regs.r_tstate &= ~0x1100000000UL;
1876 regs.r_o0 = rval;
1877 }
1878 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1879 return -1;
1880#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001881#ifdef HPPA
1882 r28 = error ? -error : rval;
1883 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1884 return -1;
1885#else
1886#ifdef SH
1887 r0 = error ? -error : rval;
1888 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1889 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001890#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001891#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001892 r9 = error ? -error : rval;
1893 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1894 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001895#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896#endif /* SH */
1897#endif /* HPPA */
1898#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001899#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001900#endif /* ALPHA */
1901#endif /* ARM */
1902#endif /* M68K */
1903#endif /* POWERPC */
1904#endif /* MIPS */
1905#endif /* IA64 */
1906#endif /* X86_64 */
1907#endif /* I386 */
1908#endif /* S390 || S390X */
1909#endif /* LINUX */
1910#ifdef SUNOS4
1911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1912 error << 24) < 0 ||
1913 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1914 return -1;
1915#endif /* SUNOS4 */
1916#ifdef SVR4
1917 /* XXX no clue */
1918 return -1;
1919#endif /* SVR4 */
1920#ifdef FREEBSD
1921 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1922 perror("pread");
1923 return -1;
1924 }
1925 if (error) {
1926 regs.r_eflags |= PSL_C;
1927 regs.r_eax = error;
1928 }
1929 else {
1930 regs.r_eflags &= ~PSL_C;
1931 regs.r_eax = rval;
1932 }
1933 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1934 perror("pwrite");
1935 return -1;
1936 }
1937#endif /* FREEBSD */
1938
1939 /* All branches reach here on success (only). */
1940 tcp->u_error = error;
1941 tcp->u_rval = rval;
1942 return 0;
1943}
1944
Roland McGratha4d48532005-06-08 20:45:28 +00001945static int
1946syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001947struct tcb *tcp;
1948{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001949#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001950 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001951#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001952#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001953#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001954 {
1955 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001956 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1957 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001958 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001960 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001961 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001962 return -1;
1963 }
1964 }
1965#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966 {
1967 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001968 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1969 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001970 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001971 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001973 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1974 * for scno somewhere above here!
1975 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1977 return -1;
1978 }
1979 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001980#elif defined (IA64)
1981 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001982 if (!ia32) {
1983 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1984 /* be backwards compatible with kernel < 2.4.4... */
1985# ifndef PT_RBS_END
1986# define PT_RBS_END PT_AR_BSP
1987# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001988
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001989 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001990 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001991 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1992 return -1;
1993
1994 sof = (cfm >> 0) & 0x7f;
1995 sol = (cfm >> 7) & 0x7f;
1996 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1997
1998 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1999 && sysent[tcp->scno].nargs != -1)
2000 tcp->u_nargs = sysent[tcp->scno].nargs;
2001 else
2002 tcp->u_nargs = MAX_ARGS;
2003 for (i = 0; i < tcp->u_nargs; ++i) {
2004 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2005 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2006 return -1;
2007 }
2008 } else {
2009 int i;
2010
2011 if (/* EBX = out0 */
2012 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
2013 /* ECX = out1 */
2014 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
2015 /* EDX = out2 */
2016 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
2017 /* ESI = out3 */
2018 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
2019 /* EDI = out4 */
2020 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
2021 /* EBP = out5 */
2022 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2023 return -1;
2024
2025 for (i = 0; i < 6; ++i)
2026 /* truncate away IVE sign-extension */
2027 tcp->u_arg[i] &= 0xffffffff;
2028
2029 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2030 && sysent[tcp->scno].nargs != -1)
2031 tcp->u_nargs = sysent[tcp->scno].nargs;
2032 else
2033 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002034 }
2035 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002036#elif defined (MIPS)
2037 {
2038 long sp;
2039 int i, nargs;
2040
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002041 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2042 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002043 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002044 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002045 if(nargs > 4) {
2046 if(upeek(pid, REG_SP, &sp) < 0)
2047 return -1;
2048 for(i = 0; i < 4; i++) {
2049 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2050 return -1;
2051 }
2052 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2053 (char *)(tcp->u_arg + 4));
2054 } else {
2055 for(i = 0; i < nargs; i++) {
2056 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2057 return -1;
2058 }
2059 }
2060 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002061#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002062#ifndef PT_ORIG_R3
2063#define PT_ORIG_R3 34
2064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 {
2066 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002067 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2068 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002069 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002070 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002071 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002072 if (upeek(pid, (i==0) ?
2073 (sizeof(unsigned long)*PT_ORIG_R3) :
2074 ((i+PT_R3)*sizeof(unsigned long)),
2075 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002076 return -1;
2077 }
2078 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002079#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002080 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002081 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002082
2083 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2084 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002085 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002086 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002087 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002088 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002090#elif defined (HPPA)
2091 {
2092 int i;
2093
2094 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2095 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002096 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002097 tcp->u_nargs = MAX_ARGS;
2098 for (i = 0; i < tcp->u_nargs; i++) {
2099 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2100 return -1;
2101 }
2102 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002103#elif defined(ARM)
2104 {
2105 int i;
2106
2107 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2108 tcp->u_nargs = sysent[tcp->scno].nargs;
2109 else
2110 tcp->u_nargs = MAX_ARGS;
2111 for (i = 0; i < tcp->u_nargs; i++)
2112 tcp->u_arg[i] = regs.uregs[i];
2113 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002114#elif defined(SH)
2115 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002116 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002117 static int syscall_regs[] = {
2118 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2119 REG_REG0, REG_REG0+1, REG_REG0+2
2120 };
2121
2122 tcp->u_nargs = sysent[tcp->scno].nargs;
2123 for (i = 0; i < tcp->u_nargs; i++) {
2124 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2125 return -1;
2126 }
2127 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002128#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002129 {
2130 int i;
2131 /* Registers used by SH5 Linux system calls for parameters */
2132 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2133
2134 /*
2135 * TODO: should also check that the number of arguments encoded
2136 * in the trap number matches the number strace expects.
2137 */
2138 /*
2139 assert(sysent[tcp->scno].nargs <
2140 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2141 */
2142
2143 tcp->u_nargs = sysent[tcp->scno].nargs;
2144 for (i = 0; i < tcp->u_nargs; i++) {
2145 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2146 return -1;
2147 }
2148 }
2149
Michal Ludvig0e035502002-09-23 15:41:01 +00002150#elif defined(X86_64)
2151 {
2152 int i;
2153 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2154 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002155 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002156 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002157
Michal Ludvig0e035502002-09-23 15:41:01 +00002158 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2159 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002160 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002161 tcp->u_nargs = MAX_ARGS;
2162 for (i = 0; i < tcp->u_nargs; i++) {
2163 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2164 return -1;
2165 }
2166 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002167#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002168 {
2169 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002170 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2171 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002172 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002173 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002174 for (i = 0; i < tcp->u_nargs; i++) {
2175 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2176 return -1;
2177 }
2178 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002179#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002180#endif /* LINUX */
2181#ifdef SUNOS4
2182 {
2183 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002184 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2185 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002186 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002187 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002188 for (i = 0; i < tcp->u_nargs; i++) {
2189 struct user *u;
2190
2191 if (upeek(pid, uoff(u_arg[0]) +
2192 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2193 return -1;
2194 }
2195 }
2196#endif /* SUNOS4 */
2197#ifdef SVR4
2198#ifdef MIPS
2199 /*
2200 * SGI is broken: even though it has pr_sysarg, it doesn't
2201 * set them on system call entry. Get a clue.
2202 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002203 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002204 tcp->u_nargs = sysent[tcp->scno].nargs;
2205 else
2206 tcp->u_nargs = tcp->status.pr_nsysarg;
2207 if (tcp->u_nargs > 4) {
2208 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2209 4*sizeof(tcp->u_arg[0]));
2210 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2211 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2212 }
2213 else {
2214 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2215 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2216 }
John Hughes25299712001-03-06 10:10:06 +00002217#elif UNIXWARE >= 2
2218 /*
2219 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2220 */
2221 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2222 tcp->u_nargs = sysent[tcp->scno].nargs;
2223 else
2224 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2225 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2226 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2227#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002228 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 tcp->u_nargs = sysent[tcp->scno].nargs;
2230 else
2231 tcp->u_nargs = tcp->status.pr_nsysarg;
2232 {
2233 int i;
2234 for (i = 0; i < tcp->u_nargs; i++)
2235 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2236 }
John Hughes25299712001-03-06 10:10:06 +00002237#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002239 tcp->u_nargs = sysent[tcp->scno].nargs;
2240 else
2241 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002242 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002244#else
2245 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002246#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002248#ifdef FREEBSD
2249 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2250 sysent[tcp->scno].nargs > tcp->status.val)
2251 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002252 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002253 tcp->u_nargs = tcp->status.val;
2254 if (tcp->u_nargs < 0)
2255 tcp->u_nargs = 0;
2256 if (tcp->u_nargs > MAX_ARGS)
2257 tcp->u_nargs = MAX_ARGS;
2258 switch(regs.r_eax) {
2259 case SYS___syscall:
2260 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2261 regs.r_esp + sizeof(int) + sizeof(quad_t));
2262 break;
2263 case SYS_syscall:
2264 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2265 regs.r_esp + 2 * sizeof(int));
2266 break;
2267 default:
2268 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2269 regs.r_esp + sizeof(int));
2270 break;
2271 }
2272#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002273 return 1;
2274}
2275
2276int
2277trace_syscall(tcp)
2278struct tcb *tcp;
2279{
2280 int sys_res;
2281 struct timeval tv;
2282 int res;
2283
2284 /* Measure the exit time as early as possible to avoid errors. */
2285 if (dtime && (tcp->flags & TCB_INSYSCALL))
2286 gettimeofday(&tv, NULL);
2287
2288 res = get_scno(tcp);
2289 if (res != 1)
2290 return res;
2291
2292 res = syscall_fixup(tcp);
2293 if (res != 1)
2294 return res;
2295
2296 if (tcp->flags & TCB_INSYSCALL) {
2297 long u_error;
2298 res = get_error(tcp);
2299 if (res != 1)
2300 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002301
2302 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002303 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2304 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002305 tcp->flags &= ~TCB_INSYSCALL;
2306 return 0;
2307 }
2308
2309 if (tcp->flags & TCB_REPRINT) {
2310 printleader(tcp);
2311 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002312 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002313 tprintf("syscall_%lu", tcp->scno);
2314 else
2315 tprintf("%s", sysent[tcp->scno].sys_name);
2316 tprintf(" resumed> ");
2317 }
2318
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002319 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002320 if (counts == NULL) {
2321 counts = calloc(sizeof *counts, nsyscalls);
2322 if (counts == NULL) {
2323 fprintf(stderr, "\
2324strace: out of memory for call counts\n");
2325 exit(1);
2326 }
2327 }
2328
2329 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002330 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002331 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002332 tv_sub(&tv, &tv, &tcp->etime);
2333#ifdef LINUX
2334 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002335 static struct timeval one_tick;
2336 if (one_tick.tv_usec == 0) {
2337 /* Initialize it. */
2338 struct itimerval it;
2339 memset(&it, 0, sizeof it);
2340 it.it_interval.tv_usec = 1;
2341 setitimer(ITIMER_REAL, &it, NULL);
2342 getitimer(ITIMER_REAL, &it);
2343 one_tick = it.it_interval;
2344 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002345
2346 if (tv_nz(&tcp->dtime))
2347 tv = tcp->dtime;
2348 else if (tv_cmp(&tv, &one_tick) > 0) {
2349 if (tv_cmp(&shortest, &one_tick) < 0)
2350 tv = shortest;
2351 else
2352 tv = one_tick;
2353 }
2354 }
2355#endif /* LINUX */
2356 if (tv_cmp(&tv, &shortest) < 0)
2357 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002358 tv_add(&counts[tcp->scno].time,
2359 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002360 tcp->flags &= ~TCB_INSYSCALL;
2361 return 0;
2362 }
2363
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002364 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002365 || (qual_flags[tcp->scno] & QUAL_RAW))
2366 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002367 else {
2368 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002369 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002371 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002372 u_error = tcp->u_error;
2373 tprintf(") ");
2374 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002375 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2376 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002377 if (u_error)
2378 tprintf("= -1 (errno %ld)", u_error);
2379 else
2380 tprintf("= %#lx", tcp->u_rval);
2381 }
2382 else if (!(sys_res & RVAL_NONE) && u_error) {
2383 switch (u_error) {
2384#ifdef LINUX
2385 case ERESTARTSYS:
2386 tprintf("= ? ERESTARTSYS (To be restarted)");
2387 break;
2388 case ERESTARTNOINTR:
2389 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2390 break;
2391 case ERESTARTNOHAND:
2392 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2393 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002394 case ERESTART_RESTARTBLOCK:
2395 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2396 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002397#endif /* LINUX */
2398 default:
2399 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002400 if (u_error < 0)
2401 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002402 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002403 tprintf("%s (%s)", errnoent[u_error],
2404 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002405 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002406 tprintf("ERRNO_%ld (%s)", u_error,
2407 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002408 break;
2409 }
2410 }
2411 else {
2412 if (sys_res & RVAL_NONE)
2413 tprintf("= ?");
2414 else {
2415 switch (sys_res & RVAL_MASK) {
2416 case RVAL_HEX:
2417 tprintf("= %#lx", tcp->u_rval);
2418 break;
2419 case RVAL_OCTAL:
2420 tprintf("= %#lo", tcp->u_rval);
2421 break;
2422 case RVAL_UDECIMAL:
2423 tprintf("= %lu", tcp->u_rval);
2424 break;
2425 case RVAL_DECIMAL:
2426 tprintf("= %ld", tcp->u_rval);
2427 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002428#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002429 case RVAL_LHEX:
2430 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002431 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002432 case RVAL_LOCTAL:
2433 tprintf("= %#llo", tcp->u_lrval);
2434 break;
2435 case RVAL_LUDECIMAL:
2436 tprintf("= %llu", tcp->u_lrval);
2437 break;
2438 case RVAL_LDECIMAL:
2439 tprintf("= %lld", tcp->u_lrval);
2440 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002441#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002442 default:
2443 fprintf(stderr,
2444 "invalid rval format\n");
2445 break;
2446 }
2447 }
2448 if ((sys_res & RVAL_STR) && tcp->auxstr)
2449 tprintf(" (%s)", tcp->auxstr);
2450 }
2451 if (dtime) {
2452 tv_sub(&tv, &tv, &tcp->etime);
2453 tprintf(" <%ld.%06ld>",
2454 (long) tv.tv_sec, (long) tv.tv_usec);
2455 }
2456 printtrailer(tcp);
2457
2458 dumpio(tcp);
2459 if (fflush(tcp->outf) == EOF)
2460 return -1;
2461 tcp->flags &= ~TCB_INSYSCALL;
2462 return 0;
2463 }
2464
2465 /* Entering system call */
2466 res = syscall_enter(tcp);
2467 if (res != 1)
2468 return res;
2469
Roland McGrath17352792005-06-07 23:21:26 +00002470 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002471#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002472#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002473 case SYS_socketcall:
2474 decode_subcall(tcp, SYS_socket_subcall,
2475 SYS_socket_nsubcalls, deref_style);
2476 break;
2477 case SYS_ipc:
2478 decode_subcall(tcp, SYS_ipc_subcall,
2479 SYS_ipc_nsubcalls, shift_style);
2480 break;
Roland McGrath17352792005-06-07 23:21:26 +00002481#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002482#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002483 case SYS_socketcall:
2484 sparc_socket_decode (tcp);
2485 break;
2486#endif
2487#endif /* LINUX */
2488#ifdef SVR4
2489#ifdef SYS_pgrpsys_subcall
2490 case SYS_pgrpsys:
2491 decode_subcall(tcp, SYS_pgrpsys_subcall,
2492 SYS_pgrpsys_nsubcalls, shift_style);
2493 break;
2494#endif /* SYS_pgrpsys_subcall */
2495#ifdef SYS_sigcall_subcall
2496 case SYS_sigcall:
2497 decode_subcall(tcp, SYS_sigcall_subcall,
2498 SYS_sigcall_nsubcalls, mask_style);
2499 break;
2500#endif /* SYS_sigcall_subcall */
2501 case SYS_msgsys:
2502 decode_subcall(tcp, SYS_msgsys_subcall,
2503 SYS_msgsys_nsubcalls, shift_style);
2504 break;
2505 case SYS_shmsys:
2506 decode_subcall(tcp, SYS_shmsys_subcall,
2507 SYS_shmsys_nsubcalls, shift_style);
2508 break;
2509 case SYS_semsys:
2510 decode_subcall(tcp, SYS_semsys_subcall,
2511 SYS_semsys_nsubcalls, shift_style);
2512 break;
2513#if 0 /* broken */
2514 case SYS_utssys:
2515 decode_subcall(tcp, SYS_utssys_subcall,
2516 SYS_utssys_nsubcalls, shift_style);
2517 break;
2518#endif
2519 case SYS_sysfs:
2520 decode_subcall(tcp, SYS_sysfs_subcall,
2521 SYS_sysfs_nsubcalls, shift_style);
2522 break;
2523 case SYS_spcall:
2524 decode_subcall(tcp, SYS_spcall_subcall,
2525 SYS_spcall_nsubcalls, shift_style);
2526 break;
2527#ifdef SYS_context_subcall
2528 case SYS_context:
2529 decode_subcall(tcp, SYS_context_subcall,
2530 SYS_context_nsubcalls, shift_style);
2531 break;
2532#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002533#ifdef SYS_door_subcall
2534 case SYS_door:
2535 decode_subcall(tcp, SYS_door_subcall,
2536 SYS_door_nsubcalls, door_style);
2537 break;
2538#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002539#ifdef SYS_kaio_subcall
2540 case SYS_kaio:
2541 decode_subcall(tcp, SYS_kaio_subcall,
2542 SYS_kaio_nsubcalls, shift_style);
2543 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002544#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002546#ifdef FREEBSD
2547 case SYS_msgsys:
2548 case SYS_shmsys:
2549 case SYS_semsys:
2550 decode_subcall(tcp, 0, 0, table_style);
2551 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002552#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002553#ifdef SUNOS4
2554 case SYS_semsys:
2555 decode_subcall(tcp, SYS_semsys_subcall,
2556 SYS_semsys_nsubcalls, shift_style);
2557 break;
2558 case SYS_msgsys:
2559 decode_subcall(tcp, SYS_msgsys_subcall,
2560 SYS_msgsys_nsubcalls, shift_style);
2561 break;
2562 case SYS_shmsys:
2563 decode_subcall(tcp, SYS_shmsys_subcall,
2564 SYS_shmsys_nsubcalls, shift_style);
2565 break;
2566#endif
2567 }
2568
2569 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002570 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002571 tcp->flags |= TCB_INSYSCALL;
2572 return 0;
2573 }
2574
2575 if (cflag) {
2576 gettimeofday(&tcp->etime, NULL);
2577 tcp->flags |= TCB_INSYSCALL;
2578 return 0;
2579 }
2580
2581 printleader(tcp);
2582 tcp->flags &= ~TCB_REPRINT;
2583 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002584 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 tprintf("syscall_%lu(", tcp->scno);
2586 else
2587 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002588 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002589 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2590 sys_res = printargs(tcp);
2591 else
2592 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2593 if (fflush(tcp->outf) == EOF)
2594 return -1;
2595 tcp->flags |= TCB_INSYSCALL;
2596 /* Measure the entrance time as late as possible to avoid errors. */
2597 if (dtime)
2598 gettimeofday(&tcp->etime, NULL);
2599 return sys_res;
2600}
2601
2602int
2603printargs(tcp)
2604struct tcb *tcp;
2605{
2606 if (entering(tcp)) {
2607 int i;
2608
2609 for (i = 0; i < tcp->u_nargs; i++)
2610 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2611 }
2612 return 0;
2613}
2614
2615long
2616getrval2(tcp)
2617struct tcb *tcp;
2618{
2619 long val = -1;
2620
2621#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002622#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002623 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002624 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2625 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002626 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002627#elif defined(SH)
2628 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2629 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002630#elif defined(IA64)
2631 if (upeek(tcp->pid, PT_R9, &val) < 0)
2632 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002633#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634#endif /* LINUX */
2635
2636#ifdef SUNOS4
2637 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2638 return -1;
2639#endif /* SUNOS4 */
2640
2641#ifdef SVR4
2642#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002643 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002644#endif /* SPARC */
2645#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002646 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002647#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002648#ifdef X86_64
2649 val = tcp->status.PR_REG[RDX];
2650#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002652 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002653#endif /* MIPS */
2654#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002655#ifdef FREEBSD
2656 struct reg regs;
2657 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2658 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002659#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 return val;
2661}
2662
2663/*
2664 * Apparently, indirect system calls have already be converted by ptrace(2),
2665 * so if you see "indir" this program has gone astray.
2666 */
2667int
2668sys_indir(tcp)
2669struct tcb *tcp;
2670{
2671 int i, scno, nargs;
2672
2673 if (entering(tcp)) {
2674 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2675 fprintf(stderr, "Bogus syscall: %u\n", scno);
2676 return 0;
2677 }
2678 nargs = sysent[scno].nargs;
2679 tprintf("%s", sysent[scno].sys_name);
2680 for (i = 0; i < nargs; i++)
2681 tprintf(", %#lx", tcp->u_arg[i+1]);
2682 }
2683 return 0;
2684}
2685
2686static int
2687time_cmp(a, b)
2688void *a;
2689void *b;
2690{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002691 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692}
2693
2694static int
2695syscall_cmp(a, b)
2696void *a;
2697void *b;
2698{
2699 return strcmp(sysent[*((int *) a)].sys_name,
2700 sysent[*((int *) b)].sys_name);
2701}
2702
2703static int
2704count_cmp(a, b)
2705void *a;
2706void *b;
2707{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002708 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709
2710 return (m < n) ? 1 : (m > n) ? -1 : 0;
2711}
2712
2713static int (*sortfun)();
2714static struct timeval overhead = { -1, -1 };
2715
2716void
2717set_sortby(sortby)
2718char *sortby;
2719{
2720 if (strcmp(sortby, "time") == 0)
2721 sortfun = time_cmp;
2722 else if (strcmp(sortby, "calls") == 0)
2723 sortfun = count_cmp;
2724 else if (strcmp(sortby, "name") == 0)
2725 sortfun = syscall_cmp;
2726 else if (strcmp(sortby, "nothing") == 0)
2727 sortfun = NULL;
2728 else {
2729 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2730 exit(1);
2731 }
2732}
2733
2734void set_overhead(n)
2735int n;
2736{
2737 overhead.tv_sec = n / 1000000;
2738 overhead.tv_usec = n % 1000000;
2739}
2740
2741void
2742call_summary(outf)
2743FILE *outf;
2744{
2745 int i, j;
2746 int call_cum, error_cum;
2747 struct timeval tv_cum, dtv;
2748 double percent;
2749 char *dashes = "-------------------------";
2750 char error_str[16];
2751
Roland McGrathe10e62a2004-09-04 04:20:43 +00002752 int *sorted_count = malloc(nsyscalls * sizeof(int));
2753
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2755 if (overhead.tv_sec == -1) {
2756 tv_mul(&overhead, &shortest, 8);
2757 tv_div(&overhead, &overhead, 10);
2758 }
2759 for (i = 0; i < nsyscalls; i++) {
2760 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002761 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002762 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002763 tv_mul(&dtv, &overhead, counts[i].calls);
2764 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2765 call_cum += counts[i].calls;
2766 error_cum += counts[i].errors;
2767 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002769 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002770 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2771 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2772 "% time", "seconds", "usecs/call",
2773 "calls", "errors", "syscall");
2774 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2775 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002776 if (counts) {
2777 for (i = 0; i < nsyscalls; i++) {
2778 j = sorted_count[i];
2779 if (counts[j].calls == 0)
2780 continue;
2781 tv_div(&dtv, &counts[j].time, counts[j].calls);
2782 if (counts[j].errors)
2783 sprintf(error_str, "%d", counts[j].errors);
2784 else
2785 error_str[0] = '\0';
2786 percent = (100.0 * tv_float(&counts[j].time)
2787 / tv_float(&tv_cum));
2788 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2789 percent, (long) counts[j].time.tv_sec,
2790 (long) counts[j].time.tv_usec,
2791 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2792 counts[j].calls,
2793 error_str, sysent[j].sys_name);
2794 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002795 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002796 free(sorted_count);
2797
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002798 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2799 dashes, dashes, dashes, dashes, dashes, dashes);
2800 if (error_cum)
2801 sprintf(error_str, "%d", error_cum);
2802 else
2803 error_str[0] = '\0';
2804 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2805 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2806 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002807
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002808}