blob: 22893a790fd5f9723fc1f7e9a2333bdbcb7f089f [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
1111 if ((scno & 0x0ff00000) != 0x0f900000) {
1112 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1113 scno);
1114 return -1;
1115 }
1116
1117 /*
1118 * Fixup the syscall number
1119 */
1120 scno &= 0x000fffff;
1121 }
1122
1123 if (tcp->flags & TCB_INSYSCALL) {
1124 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1125 tcp->flags &= ~TCB_INSYSCALL;
1126 }
1127 } else {
1128 if (!(tcp->flags & TCB_INSYSCALL)) {
1129 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1130 tcp->flags |= TCB_INSYSCALL;
1131 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 }
1133#elif defined (M68K)
1134 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1135 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001136#elif defined (MIPS)
1137 if (upeek(pid, REG_A3, &a3) < 0)
1138 return -1;
1139
1140 if(!(tcp->flags & TCB_INSYSCALL)) {
1141 if (upeek(pid, REG_V0, &scno) < 0)
1142 return -1;
1143
1144 if (scno < 0 || scno > nsyscalls) {
1145 if(a3 == 0 || a3 == -1) {
1146 if(debug)
1147 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1148 return 0;
1149 }
1150 }
1151 } else {
1152 if (upeek(pid, REG_V0, &r2) < 0)
1153 return -1;
1154 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155#elif defined (ALPHA)
1156 if (upeek(pid, REG_A3, &a3) < 0)
1157 return -1;
1158
1159 if (!(tcp->flags & TCB_INSYSCALL)) {
1160 if (upeek(pid, REG_R0, &scno) < 0)
1161 return -1;
1162
1163 /* Check if we return from execve. */
1164 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1165 tcp->flags &= ~TCB_WAITEXECVE;
1166 return 0;
1167 }
1168
1169 /*
1170 * Do some sanity checks to figure out if it's
1171 * really a syscall entry
1172 */
1173 if (scno < 0 || scno > nsyscalls) {
1174 if (a3 == 0 || a3 == -1) {
1175 if (debug)
1176 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1177 return 0;
1178 }
1179 }
1180 }
1181 else {
1182 if (upeek(pid, REG_R0, &r0) < 0)
1183 return -1;
1184 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001185#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 /* Everything we need is in the current register set. */
1187 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1188 return -1;
1189
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 /* If we are entering, then disassemble the syscall trap. */
1191 if (!(tcp->flags & TCB_INSYSCALL)) {
1192 /* Retrieve the syscall trap instruction. */
1193 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001194 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001195#if defined(SPARC64)
1196 trap >>= 32;
1197#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001198 if (errno)
1199 return -1;
1200
1201 /* Disassemble the trap to see what personality to use. */
1202 switch (trap) {
1203 case 0x91d02010:
1204 /* Linux/SPARC syscall trap. */
1205 set_personality(0);
1206 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001207 case 0x91d0206d:
1208 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001209 set_personality(2);
1210 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 case 0x91d02000:
1212 /* SunOS syscall trap. (pers 1) */
1213 fprintf(stderr,"syscall: SunOS no support\n");
1214 return -1;
1215 case 0x91d02008:
1216 /* Solaris 2.x syscall trap. (per 2) */
1217 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001218 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001219 case 0x91d02009:
1220 /* NetBSD/FreeBSD syscall trap. */
1221 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1222 return -1;
1223 case 0x91d02027:
1224 /* Solaris 2.x gettimeofday */
1225 set_personality(1);
1226 break;
1227 default:
1228 /* Unknown syscall trap. */
1229 if(tcp->flags & TCB_WAITEXECVE) {
1230 tcp->flags &= ~TCB_WAITEXECVE;
1231 return 0;
1232 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001233#if defined (SPARC64)
1234 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1235#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001236 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001237#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238 return -1;
1239 }
1240
1241 /* Extract the system call number from the registers. */
1242 if (trap == 0x91d02027)
1243 scno = 156;
1244 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001245 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001247 scno = regs.r_o0;
1248 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249 }
1250 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001251#elif defined(HPPA)
1252 if (upeek(pid, PT_GR20, &scno) < 0)
1253 return -1;
1254 if (!(tcp->flags & TCB_INSYSCALL)) {
1255 /* Check if we return from execve. */
1256 if ((tcp->flags & TCB_WAITEXECVE)) {
1257 tcp->flags &= ~TCB_WAITEXECVE;
1258 return 0;
1259 }
1260 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001261#elif defined(SH)
1262 /*
1263 * In the new syscall ABI, the system call number is in R3.
1264 */
1265 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1266 return -1;
1267
1268 if (scno < 0) {
1269 /* Odd as it may seem, a glibc bug has been known to cause
1270 glibc to issue bogus negative syscall numbers. So for
1271 our purposes, make strace print what it *should* have been */
1272 long correct_scno = (scno & 0xff);
1273 if (debug)
1274 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001275 "Detected glibc bug: bogus system call number = %ld, "
1276 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001277 scno,
1278 correct_scno);
1279 scno = correct_scno;
1280 }
1281
1282
1283 if (!(tcp->flags & TCB_INSYSCALL)) {
1284 /* Check if we return from execve. */
1285 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1286 tcp->flags &= ~TCB_WAITEXECVE;
1287 return 0;
1288 }
1289 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001290#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001291 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1292 return -1;
1293 scno &= 0xFFFF;
1294
1295 if (!(tcp->flags & TCB_INSYSCALL)) {
1296 /* Check if we return from execve. */
1297 if (tcp->flags & TCB_WAITEXECVE) {
1298 tcp->flags &= ~TCB_WAITEXECVE;
1299 return 0;
1300 }
1301 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001302#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303#endif /* LINUX */
1304#ifdef SUNOS4
1305 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1306 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001307#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001308 /* new syscall ABI returns result in R0 */
1309 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1310 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001311#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001312 /* ABI defines result returned in r9 */
1313 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1314 return -1;
1315
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001317#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001319 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001322 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001323#else /* FREEBSD */
1324 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1325 perror("pread");
1326 return -1;
1327 }
1328 switch (regs.r_eax) {
1329 case SYS_syscall:
1330 case SYS___syscall:
1331 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1332 break;
1333 default:
1334 scno = regs.r_eax;
1335 break;
1336 }
1337#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001338#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001340 if (!(tcp->flags & TCB_INSYSCALL))
1341 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001342 return 1;
1343}
1344
Pavel Machek4dc3b142000-02-01 17:58:41 +00001345
Roland McGrath17352792005-06-07 23:21:26 +00001346long
1347known_scno(tcp)
1348struct tcb *tcp;
1349{
1350 long scno = tcp->scno;
1351 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1352 scno = sysent[scno].native_scno;
1353 else
1354 scno += NR_SYSCALL_BASE;
1355 return scno;
1356}
1357
Roland McGratha4d48532005-06-08 20:45:28 +00001358static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001359syscall_fixup(tcp)
1360struct tcb *tcp;
1361{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001362#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001363 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001364#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001365 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001366
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001368 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 if (
1370 scno == SYS_fork
1371#ifdef SYS_vfork
1372 || scno == SYS_vfork
1373#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001374#ifdef SYS_fork1
1375 || scno == SYS_fork1
1376#endif /* SYS_fork1 */
1377#ifdef SYS_forkall
1378 || scno == SYS_forkall
1379#endif /* SYS_forkall */
1380#ifdef SYS_rfork1
1381 || scno == SYS_rfork1
1382#endif /* SYS_fork1 */
1383#ifdef SYS_rforkall
1384 || scno == SYS_rforkall
1385#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386 ) {
1387 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001388 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 }
1392 else {
1393 fprintf(stderr, "syscall: missing entry\n");
1394 tcp->flags |= TCB_INSYSCALL;
1395 }
1396 }
1397 }
1398 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 fprintf(stderr, "syscall: missing exit\n");
1401 tcp->flags &= ~TCB_INSYSCALL;
1402 }
1403 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001404#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405#ifdef SUNOS4
1406 if (!(tcp->flags & TCB_INSYSCALL)) {
1407 if (scno == 0) {
1408 fprintf(stderr, "syscall: missing entry\n");
1409 tcp->flags |= TCB_INSYSCALL;
1410 }
1411 }
1412 else {
1413 if (scno != 0) {
1414 if (debug) {
1415 /*
1416 * This happens when a signal handler
1417 * for a signal which interrupted a
1418 * a system call makes another system call.
1419 */
1420 fprintf(stderr, "syscall: missing exit\n");
1421 }
1422 tcp->flags &= ~TCB_INSYSCALL;
1423 }
1424 }
1425#endif /* SUNOS4 */
1426#ifdef LINUX
1427#if defined (I386)
1428 if (upeek(pid, 4*EAX, &eax) < 0)
1429 return -1;
1430 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1431 if (debug)
1432 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1433 return 0;
1434 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001435#elif defined (X86_64)
1436 if (upeek(pid, 8*RAX, &rax) < 0)
1437 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001438 if (current_personality == 1)
1439 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001440 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1441 if (debug)
1442 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1443 return 0;
1444 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001445#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001446 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1447 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001448 if (syscall_mode != -ENOSYS)
1449 syscall_mode = tcp->scno;
1450 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001451 if (debug)
1452 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1453 return 0;
1454 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001455 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1456 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1457 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1458 /*
1459 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1460 * flag set for the post-execve SIGTRAP to see and reset.
1461 */
1462 gpr2 = 0;
1463 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464#elif defined (POWERPC)
1465# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001466 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001468 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469 return -1;
1470 if (flags & SO_MASK)
1471 result = -result;
1472#elif defined (M68K)
1473 if (upeek(pid, 4*PT_D0, &d0) < 0)
1474 return -1;
1475 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1476 if (debug)
1477 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1478 return 0;
1479 }
1480#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001481 /*
1482 * Nothing required
1483 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001484#elif defined (HPPA)
1485 if (upeek(pid, PT_GR28, &r28) < 0)
1486 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001487#elif defined(IA64)
1488 if (upeek(pid, PT_R10, &r10) < 0)
1489 return -1;
1490 if (upeek(pid, PT_R8, &r8) < 0)
1491 return -1;
1492 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1493 if (debug)
1494 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1495 return 0;
1496 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497#endif
1498#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001499 return 1;
1500}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501
Roland McGratha4d48532005-06-08 20:45:28 +00001502static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001503get_error(tcp)
1504struct tcb *tcp;
1505{
1506 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001508#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001509 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1510 tcp->u_rval = -1;
1511 u_error = -gpr2;
1512 }
1513 else {
1514 tcp->u_rval = gpr2;
1515 u_error = 0;
1516 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001517#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001518#ifdef I386
1519 if (eax < 0 && -eax < nerrnos) {
1520 tcp->u_rval = -1;
1521 u_error = -eax;
1522 }
1523 else {
1524 tcp->u_rval = eax;
1525 u_error = 0;
1526 }
1527#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001528#ifdef X86_64
1529 if (rax < 0 && -rax < nerrnos) {
1530 tcp->u_rval = -1;
1531 u_error = -rax;
1532 }
1533 else {
1534 tcp->u_rval = rax;
1535 u_error = 0;
1536 }
1537#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001538#ifdef IA64
1539 if (ia32) {
1540 int err;
1541
1542 err = (int)r8;
1543 if (err < 0 && -err < nerrnos) {
1544 tcp->u_rval = -1;
1545 u_error = -err;
1546 }
1547 else {
1548 tcp->u_rval = err;
1549 u_error = 0;
1550 }
1551 } else {
1552 if (r10) {
1553 tcp->u_rval = -1;
1554 u_error = r8;
1555 } else {
1556 tcp->u_rval = r8;
1557 u_error = 0;
1558 }
1559 }
1560#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001561#ifdef MIPS
1562 if (a3) {
1563 tcp->u_rval = -1;
1564 u_error = r2;
1565 } else {
1566 tcp->u_rval = r2;
1567 u_error = 0;
1568 }
1569#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001571 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001572 tcp->u_rval = -1;
1573 u_error = -result;
1574 }
1575 else {
1576 tcp->u_rval = result;
1577 u_error = 0;
1578 }
1579#else /* !POWERPC */
1580#ifdef M68K
1581 if (d0 && (unsigned) -d0 < nerrnos) {
1582 tcp->u_rval = -1;
1583 u_error = -d0;
1584 }
1585 else {
1586 tcp->u_rval = d0;
1587 u_error = 0;
1588 }
1589#else /* !M68K */
1590#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001591 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001593 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 }
1595 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001596 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597 u_error = 0;
1598 }
1599#else /* !ARM */
1600#ifdef ALPHA
1601 if (a3) {
1602 tcp->u_rval = -1;
1603 u_error = r0;
1604 }
1605 else {
1606 tcp->u_rval = r0;
1607 u_error = 0;
1608 }
1609#else /* !ALPHA */
1610#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001611 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001613 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 }
1615 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001616 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 u_error = 0;
1618 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001619#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001620#ifdef SPARC64
1621 if (regs.r_tstate & 0x1100000000UL) {
1622 tcp->u_rval = -1;
1623 u_error = regs.r_o0;
1624 }
1625 else {
1626 tcp->u_rval = regs.r_o0;
1627 u_error = 0;
1628 }
1629#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001630#ifdef HPPA
1631 if (r28 && (unsigned) -r28 < nerrnos) {
1632 tcp->u_rval = -1;
1633 u_error = -r28;
1634 }
1635 else {
1636 tcp->u_rval = r28;
1637 u_error = 0;
1638 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001639#else
1640#ifdef SH
1641 /* interpret R0 as return value or error number */
1642 if (r0 && (unsigned) -r0 < nerrnos) {
1643 tcp->u_rval = -1;
1644 u_error = -r0;
1645 }
1646 else {
1647 tcp->u_rval = r0;
1648 u_error = 0;
1649 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001650#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001651#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001652 /* interpret result as return value or error number */
1653 if (r9 && (unsigned) -r9 < nerrnos) {
1654 tcp->u_rval = -1;
1655 u_error = -r9;
1656 }
1657 else {
1658 tcp->u_rval = r9;
1659 u_error = 0;
1660 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001661#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001662#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001663#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001665#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666#endif /* ALPHA */
1667#endif /* ARM */
1668#endif /* M68K */
1669#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001670#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001671#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001672#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001674#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#endif /* LINUX */
1676#ifdef SUNOS4
1677 /* get error code from user struct */
1678 if (upeek(pid, uoff(u_error), &u_error) < 0)
1679 return -1;
1680 u_error >>= 24; /* u_error is a char */
1681
1682 /* get system call return value */
1683 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1684 return -1;
1685#endif /* SUNOS4 */
1686#ifdef SVR4
1687#ifdef SPARC
1688 /* Judicious guessing goes a long way. */
1689 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1690 tcp->u_rval = -1;
1691 u_error = tcp->status.pr_reg[R_O0];
1692 }
1693 else {
1694 tcp->u_rval = tcp->status.pr_reg[R_O0];
1695 u_error = 0;
1696 }
1697#endif /* SPARC */
1698#ifdef I386
1699 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001700 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001701 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001702 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703 }
1704 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001705 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001706#ifdef HAVE_LONG_LONG
1707 tcp->u_lrval =
1708 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1709 tcp->status.PR_REG[EAX];
1710#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 u_error = 0;
1712 }
1713#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001714#ifdef X86_64
1715 /* Wanna know how to kill an hour single-stepping? */
1716 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1717 tcp->u_rval = -1;
1718 u_error = tcp->status.PR_REG[RAX];
1719 }
1720 else {
1721 tcp->u_rval = tcp->status.PR_REG[RAX];
1722 u_error = 0;
1723 }
1724#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001725#ifdef MIPS
1726 if (tcp->status.pr_reg[CTX_A3]) {
1727 tcp->u_rval = -1;
1728 u_error = tcp->status.pr_reg[CTX_V0];
1729 }
1730 else {
1731 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1732 u_error = 0;
1733 }
1734#endif /* MIPS */
1735#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001736#ifdef FREEBSD
1737 if (regs.r_eflags & PSL_C) {
1738 tcp->u_rval = -1;
1739 u_error = regs.r_eax;
1740 } else {
1741 tcp->u_rval = regs.r_eax;
1742 tcp->u_lrval =
1743 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1744 u_error = 0;
1745 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001746#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001747 tcp->u_error = u_error;
1748 return 1;
1749}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750
Roland McGrathb69f81b2002-12-21 23:25:18 +00001751int
1752force_result(tcp, error, rval)
1753 struct tcb *tcp;
1754 int error;
1755 long rval;
1756{
1757#ifdef LINUX
1758#if defined(S390) || defined(S390X)
1759 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001760 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1761 return -1;
1762#else /* !S390 && !S390X */
1763#ifdef I386
1764 eax = error ? -error : rval;
1765 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1766 return -1;
1767#else /* !I386 */
1768#ifdef X86_64
1769 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001770 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001771 return -1;
1772#else
1773#ifdef IA64
1774 if (ia32) {
1775 r8 = error ? -error : rval;
1776 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1777 return -1;
1778 }
1779 else {
1780 if (error) {
1781 r8 = error;
1782 r10 = -1;
1783 }
1784 else {
1785 r8 = rval;
1786 r10 = 0;
1787 }
1788 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1789 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1790 return -1;
1791 }
1792#else /* !IA64 */
1793#ifdef MIPS
1794 if (error) {
1795 r2 = error;
1796 a3 = -1;
1797 }
1798 else {
1799 r2 = rval;
1800 a3 = 0;
1801 }
1802 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1803 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1804 return -1;
1805#else
1806#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001807 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001808 return -1;
1809 if (error) {
1810 flags |= SO_MASK;
1811 result = error;
1812 }
1813 else {
1814 flags &= ~SO_MASK;
1815 result = rval;
1816 }
Roland McGratheb285352003-01-14 09:59:00 +00001817 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1818 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001819 return -1;
1820#else /* !POWERPC */
1821#ifdef M68K
1822 d0 = error ? -error : rval;
1823 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1824 return -1;
1825#else /* !M68K */
1826#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001827 regs.ARM_r0 = error ? -error : rval;
1828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829 return -1;
1830#else /* !ARM */
1831#ifdef ALPHA
1832 if (error) {
1833 a3 = -1;
1834 r0 = error;
1835 }
1836 else {
1837 a3 = 0;
1838 r0 = rval;
1839 }
1840 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1841 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1842 return -1;
1843#else /* !ALPHA */
1844#ifdef SPARC
1845 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1846 return -1;
1847 if (error) {
1848 regs.r_psr |= PSR_C;
1849 regs.r_o0 = error;
1850 }
1851 else {
1852 regs.r_psr &= ~PSR_C;
1853 regs.r_o0 = rval;
1854 }
1855 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1856 return -1;
1857#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001858#ifdef SPARC64
1859 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1860 return -1;
1861 if (error) {
1862 regs.r_tstate |= 0x1100000000UL;
1863 regs.r_o0 = error;
1864 }
1865 else {
1866 regs.r_tstate &= ~0x1100000000UL;
1867 regs.r_o0 = rval;
1868 }
1869 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1870 return -1;
1871#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001872#ifdef HPPA
1873 r28 = error ? -error : rval;
1874 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1875 return -1;
1876#else
1877#ifdef SH
1878 r0 = error ? -error : rval;
1879 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1880 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001881#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001882#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001883 r9 = error ? -error : rval;
1884 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1885 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001886#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001887#endif /* SH */
1888#endif /* HPPA */
1889#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001890#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001891#endif /* ALPHA */
1892#endif /* ARM */
1893#endif /* M68K */
1894#endif /* POWERPC */
1895#endif /* MIPS */
1896#endif /* IA64 */
1897#endif /* X86_64 */
1898#endif /* I386 */
1899#endif /* S390 || S390X */
1900#endif /* LINUX */
1901#ifdef SUNOS4
1902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1903 error << 24) < 0 ||
1904 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1905 return -1;
1906#endif /* SUNOS4 */
1907#ifdef SVR4
1908 /* XXX no clue */
1909 return -1;
1910#endif /* SVR4 */
1911#ifdef FREEBSD
1912 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1913 perror("pread");
1914 return -1;
1915 }
1916 if (error) {
1917 regs.r_eflags |= PSL_C;
1918 regs.r_eax = error;
1919 }
1920 else {
1921 regs.r_eflags &= ~PSL_C;
1922 regs.r_eax = rval;
1923 }
1924 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1925 perror("pwrite");
1926 return -1;
1927 }
1928#endif /* FREEBSD */
1929
1930 /* All branches reach here on success (only). */
1931 tcp->u_error = error;
1932 tcp->u_rval = rval;
1933 return 0;
1934}
1935
Roland McGratha4d48532005-06-08 20:45:28 +00001936static int
1937syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001938struct tcb *tcp;
1939{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001940#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001941 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001942#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001943#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001944#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001945 {
1946 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001947 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1948 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001949 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001950 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001951 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001952 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001953 return -1;
1954 }
1955 }
1956#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001957 {
1958 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1960 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001961 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001962 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001963 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001964 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1965 * for scno somewhere above here!
1966 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1968 return -1;
1969 }
1970 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001971#elif defined (IA64)
1972 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001973 if (!ia32) {
1974 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1975 /* be backwards compatible with kernel < 2.4.4... */
1976# ifndef PT_RBS_END
1977# define PT_RBS_END PT_AR_BSP
1978# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001979
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001980 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001981 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001982 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1983 return -1;
1984
1985 sof = (cfm >> 0) & 0x7f;
1986 sol = (cfm >> 7) & 0x7f;
1987 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1988
1989 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1990 && sysent[tcp->scno].nargs != -1)
1991 tcp->u_nargs = sysent[tcp->scno].nargs;
1992 else
1993 tcp->u_nargs = MAX_ARGS;
1994 for (i = 0; i < tcp->u_nargs; ++i) {
1995 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1996 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1997 return -1;
1998 }
1999 } else {
2000 int i;
2001
2002 if (/* EBX = out0 */
2003 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
2004 /* ECX = out1 */
2005 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
2006 /* EDX = out2 */
2007 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
2008 /* ESI = out3 */
2009 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
2010 /* EDI = out4 */
2011 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
2012 /* EBP = out5 */
2013 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2014 return -1;
2015
2016 for (i = 0; i < 6; ++i)
2017 /* truncate away IVE sign-extension */
2018 tcp->u_arg[i] &= 0xffffffff;
2019
2020 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2021 && sysent[tcp->scno].nargs != -1)
2022 tcp->u_nargs = sysent[tcp->scno].nargs;
2023 else
2024 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002025 }
2026 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002027#elif defined (MIPS)
2028 {
2029 long sp;
2030 int i, nargs;
2031
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002032 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2033 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002034 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002035 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002036 if(nargs > 4) {
2037 if(upeek(pid, REG_SP, &sp) < 0)
2038 return -1;
2039 for(i = 0; i < 4; i++) {
2040 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2041 return -1;
2042 }
2043 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2044 (char *)(tcp->u_arg + 4));
2045 } else {
2046 for(i = 0; i < nargs; i++) {
2047 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2048 return -1;
2049 }
2050 }
2051 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002052#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002053#ifndef PT_ORIG_R3
2054#define PT_ORIG_R3 34
2055#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002056 {
2057 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002058 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2059 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002060 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002061 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002062 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002063 if (upeek(pid, (i==0) ?
2064 (sizeof(unsigned long)*PT_ORIG_R3) :
2065 ((i+PT_R3)*sizeof(unsigned long)),
2066 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 return -1;
2068 }
2069 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002070#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002071 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002072 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073
2074 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2075 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002076 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002077 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002078 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002079 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002080 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002081#elif defined (HPPA)
2082 {
2083 int i;
2084
2085 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2086 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002087 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002088 tcp->u_nargs = MAX_ARGS;
2089 for (i = 0; i < tcp->u_nargs; i++) {
2090 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2091 return -1;
2092 }
2093 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002094#elif defined(ARM)
2095 {
2096 int i;
2097
2098 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2099 tcp->u_nargs = sysent[tcp->scno].nargs;
2100 else
2101 tcp->u_nargs = MAX_ARGS;
2102 for (i = 0; i < tcp->u_nargs; i++)
2103 tcp->u_arg[i] = regs.uregs[i];
2104 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002105#elif defined(SH)
2106 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002107 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002108 static int syscall_regs[] = {
2109 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2110 REG_REG0, REG_REG0+1, REG_REG0+2
2111 };
2112
2113 tcp->u_nargs = sysent[tcp->scno].nargs;
2114 for (i = 0; i < tcp->u_nargs; i++) {
2115 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2116 return -1;
2117 }
2118 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002119#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002120 {
2121 int i;
2122 /* Registers used by SH5 Linux system calls for parameters */
2123 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2124
2125 /*
2126 * TODO: should also check that the number of arguments encoded
2127 * in the trap number matches the number strace expects.
2128 */
2129 /*
2130 assert(sysent[tcp->scno].nargs <
2131 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2132 */
2133
2134 tcp->u_nargs = sysent[tcp->scno].nargs;
2135 for (i = 0; i < tcp->u_nargs; i++) {
2136 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2137 return -1;
2138 }
2139 }
2140
Michal Ludvig0e035502002-09-23 15:41:01 +00002141#elif defined(X86_64)
2142 {
2143 int i;
2144 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2145 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002146 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002147 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002148
Michal Ludvig0e035502002-09-23 15:41:01 +00002149 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2150 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002151 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002152 tcp->u_nargs = MAX_ARGS;
2153 for (i = 0; i < tcp->u_nargs; i++) {
2154 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2155 return -1;
2156 }
2157 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002158#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002159 {
2160 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002161 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2162 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002163 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002164 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165 for (i = 0; i < tcp->u_nargs; i++) {
2166 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2167 return -1;
2168 }
2169 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002170#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002171#endif /* LINUX */
2172#ifdef SUNOS4
2173 {
2174 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002175 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2176 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002177 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002178 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002179 for (i = 0; i < tcp->u_nargs; i++) {
2180 struct user *u;
2181
2182 if (upeek(pid, uoff(u_arg[0]) +
2183 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2184 return -1;
2185 }
2186 }
2187#endif /* SUNOS4 */
2188#ifdef SVR4
2189#ifdef MIPS
2190 /*
2191 * SGI is broken: even though it has pr_sysarg, it doesn't
2192 * set them on system call entry. Get a clue.
2193 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002194 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002195 tcp->u_nargs = sysent[tcp->scno].nargs;
2196 else
2197 tcp->u_nargs = tcp->status.pr_nsysarg;
2198 if (tcp->u_nargs > 4) {
2199 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2200 4*sizeof(tcp->u_arg[0]));
2201 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2202 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2203 }
2204 else {
2205 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2206 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2207 }
John Hughes25299712001-03-06 10:10:06 +00002208#elif UNIXWARE >= 2
2209 /*
2210 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2211 */
2212 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2213 tcp->u_nargs = sysent[tcp->scno].nargs;
2214 else
2215 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2216 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2217 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2218#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002219 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002220 tcp->u_nargs = sysent[tcp->scno].nargs;
2221 else
2222 tcp->u_nargs = tcp->status.pr_nsysarg;
2223 {
2224 int i;
2225 for (i = 0; i < tcp->u_nargs; i++)
2226 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2227 }
John Hughes25299712001-03-06 10:10:06 +00002228#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002229 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002230 tcp->u_nargs = sysent[tcp->scno].nargs;
2231 else
2232 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002233 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002234 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002235#else
2236 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002239#ifdef FREEBSD
2240 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2241 sysent[tcp->scno].nargs > tcp->status.val)
2242 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002243 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002244 tcp->u_nargs = tcp->status.val;
2245 if (tcp->u_nargs < 0)
2246 tcp->u_nargs = 0;
2247 if (tcp->u_nargs > MAX_ARGS)
2248 tcp->u_nargs = MAX_ARGS;
2249 switch(regs.r_eax) {
2250 case SYS___syscall:
2251 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2252 regs.r_esp + sizeof(int) + sizeof(quad_t));
2253 break;
2254 case SYS_syscall:
2255 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2256 regs.r_esp + 2 * sizeof(int));
2257 break;
2258 default:
2259 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2260 regs.r_esp + sizeof(int));
2261 break;
2262 }
2263#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002264 return 1;
2265}
2266
2267int
2268trace_syscall(tcp)
2269struct tcb *tcp;
2270{
2271 int sys_res;
2272 struct timeval tv;
2273 int res;
2274
2275 /* Measure the exit time as early as possible to avoid errors. */
2276 if (dtime && (tcp->flags & TCB_INSYSCALL))
2277 gettimeofday(&tv, NULL);
2278
2279 res = get_scno(tcp);
2280 if (res != 1)
2281 return res;
2282
2283 res = syscall_fixup(tcp);
2284 if (res != 1)
2285 return res;
2286
2287 if (tcp->flags & TCB_INSYSCALL) {
2288 long u_error;
2289 res = get_error(tcp);
2290 if (res != 1)
2291 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002292
2293 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2295 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002296 tcp->flags &= ~TCB_INSYSCALL;
2297 return 0;
2298 }
2299
2300 if (tcp->flags & TCB_REPRINT) {
2301 printleader(tcp);
2302 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002303 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002304 tprintf("syscall_%lu", tcp->scno);
2305 else
2306 tprintf("%s", sysent[tcp->scno].sys_name);
2307 tprintf(" resumed> ");
2308 }
2309
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002310 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002311 if (counts == NULL) {
2312 counts = calloc(sizeof *counts, nsyscalls);
2313 if (counts == NULL) {
2314 fprintf(stderr, "\
2315strace: out of memory for call counts\n");
2316 exit(1);
2317 }
2318 }
2319
2320 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002322 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002323 tv_sub(&tv, &tv, &tcp->etime);
2324#ifdef LINUX
2325 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002326 static struct timeval one_tick;
2327 if (one_tick.tv_usec == 0) {
2328 /* Initialize it. */
2329 struct itimerval it;
2330 memset(&it, 0, sizeof it);
2331 it.it_interval.tv_usec = 1;
2332 setitimer(ITIMER_REAL, &it, NULL);
2333 getitimer(ITIMER_REAL, &it);
2334 one_tick = it.it_interval;
2335 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336
2337 if (tv_nz(&tcp->dtime))
2338 tv = tcp->dtime;
2339 else if (tv_cmp(&tv, &one_tick) > 0) {
2340 if (tv_cmp(&shortest, &one_tick) < 0)
2341 tv = shortest;
2342 else
2343 tv = one_tick;
2344 }
2345 }
2346#endif /* LINUX */
2347 if (tv_cmp(&tv, &shortest) < 0)
2348 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002349 tv_add(&counts[tcp->scno].time,
2350 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002351 tcp->flags &= ~TCB_INSYSCALL;
2352 return 0;
2353 }
2354
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002355 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002356 || (qual_flags[tcp->scno] & QUAL_RAW))
2357 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002358 else {
2359 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002360 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002361 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002362 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002363 u_error = tcp->u_error;
2364 tprintf(") ");
2365 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002366 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2367 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002368 if (u_error)
2369 tprintf("= -1 (errno %ld)", u_error);
2370 else
2371 tprintf("= %#lx", tcp->u_rval);
2372 }
2373 else if (!(sys_res & RVAL_NONE) && u_error) {
2374 switch (u_error) {
2375#ifdef LINUX
2376 case ERESTARTSYS:
2377 tprintf("= ? ERESTARTSYS (To be restarted)");
2378 break;
2379 case ERESTARTNOINTR:
2380 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2381 break;
2382 case ERESTARTNOHAND:
2383 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2384 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002385 case ERESTART_RESTARTBLOCK:
2386 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2387 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002388#endif /* LINUX */
2389 default:
2390 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002391 if (u_error < 0)
2392 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002393 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002394 tprintf("%s (%s)", errnoent[u_error],
2395 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002396 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002397 tprintf("ERRNO_%ld (%s)", u_error,
2398 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002399 break;
2400 }
2401 }
2402 else {
2403 if (sys_res & RVAL_NONE)
2404 tprintf("= ?");
2405 else {
2406 switch (sys_res & RVAL_MASK) {
2407 case RVAL_HEX:
2408 tprintf("= %#lx", tcp->u_rval);
2409 break;
2410 case RVAL_OCTAL:
2411 tprintf("= %#lo", tcp->u_rval);
2412 break;
2413 case RVAL_UDECIMAL:
2414 tprintf("= %lu", tcp->u_rval);
2415 break;
2416 case RVAL_DECIMAL:
2417 tprintf("= %ld", tcp->u_rval);
2418 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002419#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002420 case RVAL_LHEX:
2421 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002422 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002423 case RVAL_LOCTAL:
2424 tprintf("= %#llo", tcp->u_lrval);
2425 break;
2426 case RVAL_LUDECIMAL:
2427 tprintf("= %llu", tcp->u_lrval);
2428 break;
2429 case RVAL_LDECIMAL:
2430 tprintf("= %lld", tcp->u_lrval);
2431 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002432#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002433 default:
2434 fprintf(stderr,
2435 "invalid rval format\n");
2436 break;
2437 }
2438 }
2439 if ((sys_res & RVAL_STR) && tcp->auxstr)
2440 tprintf(" (%s)", tcp->auxstr);
2441 }
2442 if (dtime) {
2443 tv_sub(&tv, &tv, &tcp->etime);
2444 tprintf(" <%ld.%06ld>",
2445 (long) tv.tv_sec, (long) tv.tv_usec);
2446 }
2447 printtrailer(tcp);
2448
2449 dumpio(tcp);
2450 if (fflush(tcp->outf) == EOF)
2451 return -1;
2452 tcp->flags &= ~TCB_INSYSCALL;
2453 return 0;
2454 }
2455
2456 /* Entering system call */
2457 res = syscall_enter(tcp);
2458 if (res != 1)
2459 return res;
2460
Roland McGrath17352792005-06-07 23:21:26 +00002461 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002462#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002463#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002464 case SYS_socketcall:
2465 decode_subcall(tcp, SYS_socket_subcall,
2466 SYS_socket_nsubcalls, deref_style);
2467 break;
2468 case SYS_ipc:
2469 decode_subcall(tcp, SYS_ipc_subcall,
2470 SYS_ipc_nsubcalls, shift_style);
2471 break;
Roland McGrath17352792005-06-07 23:21:26 +00002472#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002473#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002474 case SYS_socketcall:
2475 sparc_socket_decode (tcp);
2476 break;
2477#endif
2478#endif /* LINUX */
2479#ifdef SVR4
2480#ifdef SYS_pgrpsys_subcall
2481 case SYS_pgrpsys:
2482 decode_subcall(tcp, SYS_pgrpsys_subcall,
2483 SYS_pgrpsys_nsubcalls, shift_style);
2484 break;
2485#endif /* SYS_pgrpsys_subcall */
2486#ifdef SYS_sigcall_subcall
2487 case SYS_sigcall:
2488 decode_subcall(tcp, SYS_sigcall_subcall,
2489 SYS_sigcall_nsubcalls, mask_style);
2490 break;
2491#endif /* SYS_sigcall_subcall */
2492 case SYS_msgsys:
2493 decode_subcall(tcp, SYS_msgsys_subcall,
2494 SYS_msgsys_nsubcalls, shift_style);
2495 break;
2496 case SYS_shmsys:
2497 decode_subcall(tcp, SYS_shmsys_subcall,
2498 SYS_shmsys_nsubcalls, shift_style);
2499 break;
2500 case SYS_semsys:
2501 decode_subcall(tcp, SYS_semsys_subcall,
2502 SYS_semsys_nsubcalls, shift_style);
2503 break;
2504#if 0 /* broken */
2505 case SYS_utssys:
2506 decode_subcall(tcp, SYS_utssys_subcall,
2507 SYS_utssys_nsubcalls, shift_style);
2508 break;
2509#endif
2510 case SYS_sysfs:
2511 decode_subcall(tcp, SYS_sysfs_subcall,
2512 SYS_sysfs_nsubcalls, shift_style);
2513 break;
2514 case SYS_spcall:
2515 decode_subcall(tcp, SYS_spcall_subcall,
2516 SYS_spcall_nsubcalls, shift_style);
2517 break;
2518#ifdef SYS_context_subcall
2519 case SYS_context:
2520 decode_subcall(tcp, SYS_context_subcall,
2521 SYS_context_nsubcalls, shift_style);
2522 break;
2523#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002524#ifdef SYS_door_subcall
2525 case SYS_door:
2526 decode_subcall(tcp, SYS_door_subcall,
2527 SYS_door_nsubcalls, door_style);
2528 break;
2529#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002530#ifdef SYS_kaio_subcall
2531 case SYS_kaio:
2532 decode_subcall(tcp, SYS_kaio_subcall,
2533 SYS_kaio_nsubcalls, shift_style);
2534 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002535#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002536#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002537#ifdef FREEBSD
2538 case SYS_msgsys:
2539 case SYS_shmsys:
2540 case SYS_semsys:
2541 decode_subcall(tcp, 0, 0, table_style);
2542 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002543#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002544#ifdef SUNOS4
2545 case SYS_semsys:
2546 decode_subcall(tcp, SYS_semsys_subcall,
2547 SYS_semsys_nsubcalls, shift_style);
2548 break;
2549 case SYS_msgsys:
2550 decode_subcall(tcp, SYS_msgsys_subcall,
2551 SYS_msgsys_nsubcalls, shift_style);
2552 break;
2553 case SYS_shmsys:
2554 decode_subcall(tcp, SYS_shmsys_subcall,
2555 SYS_shmsys_nsubcalls, shift_style);
2556 break;
2557#endif
2558 }
2559
2560 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002561 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002562 tcp->flags |= TCB_INSYSCALL;
2563 return 0;
2564 }
2565
2566 if (cflag) {
2567 gettimeofday(&tcp->etime, NULL);
2568 tcp->flags |= TCB_INSYSCALL;
2569 return 0;
2570 }
2571
2572 printleader(tcp);
2573 tcp->flags &= ~TCB_REPRINT;
2574 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002575 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002576 tprintf("syscall_%lu(", tcp->scno);
2577 else
2578 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002579 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002580 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2581 sys_res = printargs(tcp);
2582 else
2583 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2584 if (fflush(tcp->outf) == EOF)
2585 return -1;
2586 tcp->flags |= TCB_INSYSCALL;
2587 /* Measure the entrance time as late as possible to avoid errors. */
2588 if (dtime)
2589 gettimeofday(&tcp->etime, NULL);
2590 return sys_res;
2591}
2592
2593int
2594printargs(tcp)
2595struct tcb *tcp;
2596{
2597 if (entering(tcp)) {
2598 int i;
2599
2600 for (i = 0; i < tcp->u_nargs; i++)
2601 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2602 }
2603 return 0;
2604}
2605
2606long
2607getrval2(tcp)
2608struct tcb *tcp;
2609{
2610 long val = -1;
2611
2612#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002613#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002614 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2616 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002617 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002618#elif defined(SH)
2619 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2620 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002621#elif defined(IA64)
2622 if (upeek(tcp->pid, PT_R9, &val) < 0)
2623 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002624#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002625#endif /* LINUX */
2626
2627#ifdef SUNOS4
2628 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2629 return -1;
2630#endif /* SUNOS4 */
2631
2632#ifdef SVR4
2633#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002634 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635#endif /* SPARC */
2636#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002637 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002638#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002639#ifdef X86_64
2640 val = tcp->status.PR_REG[RDX];
2641#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002643 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002644#endif /* MIPS */
2645#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002646#ifdef FREEBSD
2647 struct reg regs;
2648 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2649 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002650#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 return val;
2652}
2653
2654/*
2655 * Apparently, indirect system calls have already be converted by ptrace(2),
2656 * so if you see "indir" this program has gone astray.
2657 */
2658int
2659sys_indir(tcp)
2660struct tcb *tcp;
2661{
2662 int i, scno, nargs;
2663
2664 if (entering(tcp)) {
2665 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2666 fprintf(stderr, "Bogus syscall: %u\n", scno);
2667 return 0;
2668 }
2669 nargs = sysent[scno].nargs;
2670 tprintf("%s", sysent[scno].sys_name);
2671 for (i = 0; i < nargs; i++)
2672 tprintf(", %#lx", tcp->u_arg[i+1]);
2673 }
2674 return 0;
2675}
2676
2677static int
2678time_cmp(a, b)
2679void *a;
2680void *b;
2681{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002682 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683}
2684
2685static int
2686syscall_cmp(a, b)
2687void *a;
2688void *b;
2689{
2690 return strcmp(sysent[*((int *) a)].sys_name,
2691 sysent[*((int *) b)].sys_name);
2692}
2693
2694static int
2695count_cmp(a, b)
2696void *a;
2697void *b;
2698{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002699 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700
2701 return (m < n) ? 1 : (m > n) ? -1 : 0;
2702}
2703
2704static int (*sortfun)();
2705static struct timeval overhead = { -1, -1 };
2706
2707void
2708set_sortby(sortby)
2709char *sortby;
2710{
2711 if (strcmp(sortby, "time") == 0)
2712 sortfun = time_cmp;
2713 else if (strcmp(sortby, "calls") == 0)
2714 sortfun = count_cmp;
2715 else if (strcmp(sortby, "name") == 0)
2716 sortfun = syscall_cmp;
2717 else if (strcmp(sortby, "nothing") == 0)
2718 sortfun = NULL;
2719 else {
2720 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2721 exit(1);
2722 }
2723}
2724
2725void set_overhead(n)
2726int n;
2727{
2728 overhead.tv_sec = n / 1000000;
2729 overhead.tv_usec = n % 1000000;
2730}
2731
2732void
2733call_summary(outf)
2734FILE *outf;
2735{
2736 int i, j;
2737 int call_cum, error_cum;
2738 struct timeval tv_cum, dtv;
2739 double percent;
2740 char *dashes = "-------------------------";
2741 char error_str[16];
2742
Roland McGrathe10e62a2004-09-04 04:20:43 +00002743 int *sorted_count = malloc(nsyscalls * sizeof(int));
2744
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2746 if (overhead.tv_sec == -1) {
2747 tv_mul(&overhead, &shortest, 8);
2748 tv_div(&overhead, &overhead, 10);
2749 }
2750 for (i = 0; i < nsyscalls; i++) {
2751 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002752 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002754 tv_mul(&dtv, &overhead, counts[i].calls);
2755 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2756 call_cum += counts[i].calls;
2757 error_cum += counts[i].errors;
2758 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002759 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002760 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002761 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2762 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2763 "% time", "seconds", "usecs/call",
2764 "calls", "errors", "syscall");
2765 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2766 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002767 if (counts) {
2768 for (i = 0; i < nsyscalls; i++) {
2769 j = sorted_count[i];
2770 if (counts[j].calls == 0)
2771 continue;
2772 tv_div(&dtv, &counts[j].time, counts[j].calls);
2773 if (counts[j].errors)
2774 sprintf(error_str, "%d", counts[j].errors);
2775 else
2776 error_str[0] = '\0';
2777 percent = (100.0 * tv_float(&counts[j].time)
2778 / tv_float(&tv_cum));
2779 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2780 percent, (long) counts[j].time.tv_sec,
2781 (long) counts[j].time.tv_usec,
2782 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2783 counts[j].calls,
2784 error_str, sysent[j].sys_name);
2785 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002786 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002787 free(sorted_count);
2788
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002789 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2790 dashes, dashes, dashes, dashes, dashes, dashes);
2791 if (error_cum)
2792 sprintf(error_str, "%d", error_cum);
2793 else
2794 error_str[0] = '\0';
2795 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2796 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2797 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002799}