blob: f5ce8d1bd59f88dacf5d3b8c88339c072036a93d [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
186int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000187set_personality(personality)
188int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000189{
190 switch (personality) {
191 case 0:
192 errnoent = errnoent0;
193 nerrnos = nerrnos0;
194 sysent = sysent0;
195 nsyscalls = nsyscalls0;
196 ioctlent = ioctlent0;
197 nioctlents = nioctlents0;
198 signalent = signalent0;
199 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000200 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201 break;
202
203#if SUPPORTED_PERSONALITIES >= 2
204 case 1:
205 errnoent = errnoent1;
206 nerrnos = nerrnos1;
207 sysent = sysent1;
208 nsyscalls = nsyscalls1;
209 ioctlent = ioctlent1;
210 nioctlents = nioctlents1;
211 signalent = signalent1;
212 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000213 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214 break;
215#endif /* SUPPORTED_PERSONALITIES >= 2 */
216
217#if SUPPORTED_PERSONALITIES >= 3
218 case 2:
219 errnoent = errnoent2;
220 nerrnos = nerrnos2;
221 sysent = sysent2;
222 nsyscalls = nsyscalls2;
223 ioctlent = ioctlent2;
224 nioctlents = nioctlents2;
225 signalent = signalent2;
226 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000227 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000228 break;
229#endif /* SUPPORTED_PERSONALITIES >= 3 */
230
231 default:
232 return -1;
233 }
234
235 current_personality = personality;
236 return 0;
237}
238
Roland McGrathe10e62a2004-09-04 04:20:43 +0000239
240struct call_counts {
241 struct timeval time;
242 int calls, errors;
243};
244
245static struct call_counts *counts;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000246
247static struct timeval shortest = { 1000000, 0 };
248
Roland McGrath9797ceb2002-12-30 10:23:00 +0000249static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000252 int bitflag;
253 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000254 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 char *argument_name;
256} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 { QUAL_TRACE, "trace", qual_syscall, "system call" },
258 { QUAL_TRACE, "t", qual_syscall, "system call" },
259 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
260 { QUAL_ABBREV, "a", qual_syscall, "system call" },
261 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
262 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
263 { QUAL_RAW, "raw", qual_syscall, "system call" },
264 { QUAL_RAW, "x", qual_syscall, "system call" },
265 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
266 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
267 { QUAL_SIGNAL, "s", qual_signal, "signal" },
268 { QUAL_FAULT, "fault", qual_fault, "fault" },
269 { QUAL_FAULT, "faults", qual_fault, "fault" },
270 { QUAL_FAULT, "m", qual_fault, "fault" },
271 { QUAL_READ, "read", qual_desc, "descriptor" },
272 { QUAL_READ, "reads", qual_desc, "descriptor" },
273 { QUAL_READ, "r", qual_desc, "descriptor" },
274 { QUAL_WRITE, "write", qual_desc, "descriptor" },
275 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
276 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277 { 0, NULL, NULL, NULL },
278};
279
Roland McGrath9797ceb2002-12-30 10:23:00 +0000280static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000281qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000282 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000283 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000284 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000285 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286{
Roland McGrath138c6a32006-01-12 09:50:49 +0000287 if (pers == 0 || pers < 0) {
288 if (not)
289 qual_flags0[n] &= ~opt->bitflag;
290 else
291 qual_flags0[n] |= opt->bitflag;
292 }
293
294#if SUPPORTED_PERSONALITIES >= 2
295 if (pers == 1 || pers < 0) {
296 if (not)
297 qual_flags1[n] &= ~opt->bitflag;
298 else
299 qual_flags1[n] |= opt->bitflag;
300 }
301#endif /* SUPPORTED_PERSONALITIES >= 2 */
302
303#if SUPPORTED_PERSONALITIES >= 3
304 if (pers == 2 || pers < 0) {
305 if (not)
306 qual_flags2[n] &= ~opt->bitflag;
307 else
308 qual_flags2[n] |= opt->bitflag;
309 }
310#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000311}
312
313static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000314qual_syscall(s, opt, not)
315 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000316 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317 int not;
318{
319 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000320 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000321
Roland McGrath48a035f2006-01-12 09:45:56 +0000322 if (isdigit((unsigned char)*s)) {
323 int i = atoi(s);
324 if (i < 0 || i >= nsyscalls)
325 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000326 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000327 return 0;
328 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000329 for (i = 0; i < nsyscalls; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 if (strcmp(s, sysent0[i].sys_name) == 0) {
331 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000332 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000333 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000334
335#if SUPPORTED_PERSONALITIES >= 2
336 if (strcmp(s, sysent1[i].sys_name) == 0) {
337 qualify_one(i, opt, not, 1);
338 rc = 0;
339 }
340#endif /* SUPPORTED_PERSONALITIES >= 2 */
341
342#if SUPPORTED_PERSONALITIES >= 3
343 if (strcmp(s, sysent2[i].sys_name) == 0) {
344 qualify_one(i, opt, not, 2);
345 rc = 0;
346 }
347#endif /* SUPPORTED_PERSONALITIES >= 3 */
Roland McGrath9797ceb2002-12-30 10:23:00 +0000348 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000349 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000350}
351
352static int
353qual_signal(s, opt, not)
354 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000355 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000356 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000357{
358 int i;
359 char buf[32];
360
Roland McGrath48a035f2006-01-12 09:45:56 +0000361 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000362 int signo = atoi(s);
363 if (signo < 0 || signo >= MAX_QUALS)
364 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000365 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000366 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000367 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000368 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000369 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000370 strcpy(buf, s);
371 s = buf;
372 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000373 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 if (strncmp(s, "SIG", 3) == 0)
375 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000376 for (i = 0; i <= NSIG; i++)
377 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000378 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000379 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000380 }
Roland McGrath76421df2005-02-02 03:51:18 +0000381 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000382}
383
384static int
385qual_fault(s, opt, not)
386 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000387 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000388 int not;
389{
390 return -1;
391}
392
393static int
394qual_desc(s, opt, not)
395 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000396 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000397 int not;
398{
Roland McGrath48a035f2006-01-12 09:45:56 +0000399 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000400 int desc = atoi(s);
401 if (desc < 0 || desc >= MAX_QUALS)
402 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000403 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000404 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405 }
406 return -1;
407}
408
409static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000411 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000412{
413 if (strcmp(s, "file") == 0)
414 return TRACE_FILE;
415 if (strcmp(s, "ipc") == 0)
416 return TRACE_IPC;
417 if (strcmp(s, "network") == 0)
418 return TRACE_NETWORK;
419 if (strcmp(s, "process") == 0)
420 return TRACE_PROCESS;
421 if (strcmp(s, "signal") == 0)
422 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000423 if (strcmp(s, "desc") == 0)
424 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000425 return -1;
426}
427
428void
429qualify(s)
430char *s;
431{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000432 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000433 int not;
434 char *p;
435 int i, n;
436
437 opt = &qual_options[0];
438 for (i = 0; (p = qual_options[i].option_name); i++) {
439 n = strlen(p);
440 if (strncmp(s, p, n) == 0 && s[n] == '=') {
441 opt = &qual_options[i];
442 s += n + 1;
443 break;
444 }
445 }
446 not = 0;
447 if (*s == '!') {
448 not = 1;
449 s++;
450 }
451 if (strcmp(s, "none") == 0) {
452 not = 1 - not;
453 s = "all";
454 }
455 if (strcmp(s, "all") == 0) {
456 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000457 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000458 }
459 return;
460 }
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
465 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 if (sysent0[i].sys_flags & n)
468 qualify_one(i, opt, not, 0);
469
470#if SUPPORTED_PERSONALITIES >= 2
471 if (sysent1[i].sys_flags & n)
472 qualify_one(i, opt, not, 1);
473#endif /* SUPPORTED_PERSONALITIES >= 2 */
474
475#if SUPPORTED_PERSONALITIES >= 3
476 if (sysent2[i].sys_flags & n)
477 qualify_one(i, opt, not, 2);
478#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 }
480 continue;
481 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000482 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000483 fprintf(stderr, "strace: invalid %s `%s'\n",
484 opt->argument_name, p);
485 exit(1);
486 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 }
488 return;
489}
490
491static void
492dumpio(tcp)
493struct tcb *tcp;
494{
495 if (syserror(tcp))
496 return;
497 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
498 return;
Roland McGrath17352792005-06-07 23:21:26 +0000499 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000501#ifdef SYS_pread64
502 case SYS_pread64:
503#endif
504#if defined SYS_pread && SYS_pread64 != SYS_pread
505 case SYS_pread:
506#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507#ifdef SYS_recv
508 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000509#elif defined SYS_sub_recv
510 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000511#endif
512#ifdef SYS_recvfrom
513 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000514#elif defined SYS_sub_recvfrom
515 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516#endif
517 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
518 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
519 break;
520 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000521#ifdef SYS_pwrite64
522 case SYS_pwrite64:
523#endif
524#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
525 case SYS_pwrite:
526#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527#ifdef SYS_send
528 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000529#elif defined SYS_sub_send
530 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531#endif
532#ifdef SYS_sendto
533 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000534#elif defined SYS_sub_sendto
535 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536#endif
537 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
538 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
539 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000540#ifdef SYS_readv
541 case SYS_readv:
542 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
543 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
544 break;
545#endif
546#ifdef SYS_writev
547 case SYS_writev:
548
549 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
552#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553 }
554}
555
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000556#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000557enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000558#else /* FREEBSD */
559enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
560
561struct subcall {
562 int call;
563 int nsubcalls;
564 int subcalls[5];
565};
566
Roland McGratha4d48532005-06-08 20:45:28 +0000567static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000568 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000569#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000570 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000571#else
572 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
573#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000574 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
575};
576#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000578#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579
Roland McGratha4d48532005-06-08 20:45:28 +0000580static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 /* SYS_SOCKET */ 97,
582 /* SYS_BIND */ 104,
583 /* SYS_CONNECT */ 98,
584 /* SYS_LISTEN */ 106,
585 /* SYS_ACCEPT */ 99,
586 /* SYS_GETSOCKNAME */ 150,
587 /* SYS_GETPEERNAME */ 141,
588 /* SYS_SOCKETPAIR */ 135,
589 /* SYS_SEND */ 101,
590 /* SYS_RECV */ 102,
591 /* SYS_SENDTO */ 133,
592 /* SYS_RECVFROM */ 125,
593 /* SYS_SHUTDOWN */ 134,
594 /* SYS_SETSOCKOPT */ 105,
595 /* SYS_GETSOCKOPT */ 118,
596 /* SYS_SENDMSG */ 114,
597 /* SYS_RECVMSG */ 113
598};
599
Roland McGratha4d48532005-06-08 20:45:28 +0000600#if defined (SPARC) || defined (SPARC64)
601static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000602sparc_socket_decode (tcp)
603struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000604{
605 volatile long addr;
606 volatile int i, n;
607
608 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
609 return;
610 }
611 tcp->scno = socket_map [tcp->u_arg [0]-1];
612 n = tcp->u_nargs = sysent [tcp->scno].nargs;
613 addr = tcp->u_arg [1];
614 for (i = 0; i < n; i++){
615 int arg;
616 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
617 arg = 0;
618 tcp->u_arg [i] = arg;
619 addr += sizeof (arg);
620 }
621}
Roland McGratha4d48532005-06-08 20:45:28 +0000622#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000623
Roland McGratha4d48532005-06-08 20:45:28 +0000624static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625decode_subcall(tcp, subcall, nsubcalls, style)
626struct tcb *tcp;
627int subcall;
628int nsubcalls;
629enum subcall_style style;
630{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000631 long addr, mask, arg;
632 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000633
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634 switch (style) {
635 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000636 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
637 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638 tcp->scno = subcall + tcp->u_arg[0];
639 if (sysent[tcp->scno].nargs != -1)
640 tcp->u_nargs = sysent[tcp->scno].nargs;
641 else
642 tcp->u_nargs--;
643 for (i = 0; i < tcp->u_nargs; i++)
644 tcp->u_arg[i] = tcp->u_arg[i + 1];
645 break;
646 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000647 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
648 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649 tcp->scno = subcall + tcp->u_arg[0];
650 addr = tcp->u_arg[1];
651 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
652 if (umove(tcp, addr, &arg) < 0)
653 arg = 0;
654 tcp->u_arg[i] = arg;
655 addr += sizeof(arg);
656 }
657 tcp->u_nargs = sysent[tcp->scno].nargs;
658 break;
659 case mask_style:
660 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661 for (i = 0; mask; i++)
662 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000663 if (i >= nsubcalls)
664 return;
665 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000666 tcp->scno = subcall + i;
667 if (sysent[tcp->scno].nargs != -1)
668 tcp->u_nargs = sysent[tcp->scno].nargs;
669 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000670 case door_style:
671 /*
672 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000673 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000674 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000675 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
676 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000677 tcp->scno = subcall + tcp->u_arg[5];
678 if (sysent[tcp->scno].nargs != -1)
679 tcp->u_nargs = sysent[tcp->scno].nargs;
680 else
681 tcp->u_nargs--;
682 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000683#ifdef FREEBSD
684 case table_style:
685 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
686 if (subcalls_table[i].call == tcp->scno) break;
687 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
688 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
689 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
690 for (i = 0; i < tcp->u_nargs; i++)
691 tcp->u_arg[i] = tcp->u_arg[i + 1];
692 }
693 break;
694#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000695 }
696}
697#endif
698
699struct tcb *tcp_last = NULL;
700
701static int
702internal_syscall(tcp)
703struct tcb *tcp;
704{
705 /*
706 * We must always trace a few critical system calls in order to
707 * correctly support following forks in the presence of tracing
708 * qualifiers.
709 */
Roland McGrath17352792005-06-07 23:21:26 +0000710 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711#ifdef SYS_fork
712 case SYS_fork:
713#endif
714#ifdef SYS_vfork
715 case SYS_vfork:
716#endif
John Hughes4e36a812001-04-18 15:11:51 +0000717#ifdef SYS_fork1
718 case SYS_fork1:
719#endif
720#ifdef SYS_forkall
721 case SYS_forkall:
722#endif
723#ifdef SYS_rfork1
724 case SYS_rfork1:
725#endif
726#ifdef SYS_rforkall
727 case SYS_rforkall:
728#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000729#ifdef SYS_rfork
730 case SYS_rfork:
731#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732 internal_fork(tcp);
733 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000734#ifdef SYS_clone
735 case SYS_clone:
736 internal_clone(tcp);
737 break;
738#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000739#ifdef SYS_clone2
740 case SYS_clone2:
741 internal_clone(tcp);
742 break;
743#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744#ifdef SYS_execv
745 case SYS_execv:
746#endif
747#ifdef SYS_execve
748 case SYS_execve:
749#endif
John Hughes4e36a812001-04-18 15:11:51 +0000750#ifdef SYS_rexecve
751 case SYS_rexecve:
752#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753 internal_exec(tcp);
754 break;
755
756#ifdef SYS_wait
757 case SYS_wait:
758#endif
759#ifdef SYS_wait4
760 case SYS_wait4:
761#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000762#ifdef SYS32_wait4
763 case SYS32_wait4:
764#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765#ifdef SYS_waitpid
766 case SYS_waitpid:
767#endif
768#ifdef SYS_waitsys
769 case SYS_waitsys:
770#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000771 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000773#ifdef SYS_waitid
774 case SYS_waitid:
775 internal_wait(tcp, 3);
776 break;
777#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778
779#ifdef SYS_exit
780 case SYS_exit:
781#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000782#ifdef SYS32_exit
783 case SYS32_exit:
784#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000785#ifdef __NR_exit_group
786 case __NR_exit_group:
787#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000788#ifdef IA64
789 case 252: /* IA-32 __NR_exit_group */
790#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791 internal_exit(tcp);
792 break;
793 }
794 return 0;
795}
796
Wichert Akkermanc7926982000-04-10 22:22:31 +0000797
798#ifdef LINUX
799#if defined (I386)
800 static long eax;
801#elif defined (IA64)
802 long r8, r10, psr;
803 long ia32 = 0;
804#elif defined (POWERPC)
805 static long result,flags;
806#elif defined (M68K)
807 static int d0;
808#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000809 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000810#elif defined (ALPHA)
811 static long r0;
812 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000813#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000814 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000815 static unsigned long trap;
816#elif defined(MIPS)
817 static long a3;
818 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000819#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000820 static long gpr2;
821 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000823#elif defined(HPPA)
824 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000825#elif defined(SH)
826 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000827#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000828 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000829#elif defined(X86_64)
830 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000831#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000832#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000833#ifdef FREEBSD
834 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000835#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000836
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000838get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839struct tcb *tcp;
840{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000842#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000844#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000847#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000848 if (tcp->flags & TCB_WAITEXECVE) {
849 /*
850 * When the execve system call completes successfully, the
851 * new process still has -ENOSYS (old style) or __NR_execve
852 * (new style) in gpr2. We cannot recover the scno again
853 * by disassembly, because the image that executed the
854 * syscall is gone now. Fortunately, we don't want it. We
855 * leave the flag set so that syscall_fixup can fake the
856 * result.
857 */
858 if (tcp->flags & TCB_INSYSCALL)
859 return 1;
860 /*
861 * This is the SIGTRAP after execve. We cannot try to read
862 * the system call here either.
863 */
864 tcp->flags &= ~TCB_WAITEXECVE;
865 return 0;
866 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000867
868 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
869 return -1;
870
871 if (syscall_mode != -ENOSYS) {
872 /*
873 * Since kernel version 2.5.44 the scno gets passed in gpr2.
874 */
875 scno = syscall_mode;
876 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000877 /*
878 * Old style of "passing" the scno via the SVC instruction.
879 */
880
881 long opcode, offset_reg, tmp;
882 void * svc_addr;
883 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
884 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
885 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
886 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000887
Michal Ludvig882eda82002-11-11 12:50:47 +0000888 if (upeek(pid, PT_PSWADDR, &pc) < 0)
889 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000890 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000891 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000892 if (errno) {
893 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000894 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000895 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000896
897 /*
898 * We have to check if the SVC got executed directly or via an
899 * EXECUTE instruction. In case of EXECUTE it is necessary to do
900 * instruction decoding to derive the system call number.
901 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
902 * so that this doesn't work if a SVC opcode is part of an EXECUTE
903 * opcode. Since there is no way to find out the opcode size this
904 * is the best we can do...
905 */
906
907 if ((opcode & 0xff00) == 0x0a00) {
908 /* SVC opcode */
909 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000910 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000911 else {
912 /* SVC got executed by EXECUTE instruction */
913
914 /*
915 * Do instruction decoding of EXECUTE. If you really want to
916 * understand this, read the Principles of Operations.
917 */
918 svc_addr = (void *) (opcode & 0xfff);
919
920 tmp = 0;
921 offset_reg = (opcode & 0x000f0000) >> 16;
922 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
923 return -1;
924 svc_addr += tmp;
925
926 tmp = 0;
927 offset_reg = (opcode & 0x0000f000) >> 12;
928 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
929 return -1;
930 svc_addr += tmp;
931
932 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
933 if (errno)
934 return -1;
935#if defined(S390X)
936 scno >>= 48;
937#else
938 scno >>= 16;
939#endif
940 tmp = 0;
941 offset_reg = (opcode & 0x00f00000) >> 20;
942 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
943 return -1;
944
945 scno = (scno | tmp) & 0xff;
946 }
947 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000948#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000949 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 return -1;
951 if (!(tcp->flags & TCB_INSYSCALL)) {
952 /* Check if we return from execve. */
953 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
954 tcp->flags &= ~TCB_WAITEXECVE;
955 return 0;
956 }
957 }
958#elif defined (I386)
959 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
960 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000961#elif defined (X86_64)
962 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
963 return -1;
964
Roland McGrath761b5d72002-12-15 23:58:31 +0000965 if (!(tcp->flags & TCB_INSYSCALL)) {
966 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000967 long val;
968
969 /* Check CS register value. On x86-64 linux it is:
970 * 0x33 for long mode (64 bit)
971 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000972 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000973 * to be cached.
974 */
975 if (upeek(pid, 8*CS, &val) < 0)
976 return -1;
977 switch(val)
978 {
979 case 0x23: currpers = 1; break;
980 case 0x33: currpers = 0; break;
981 default:
982 fprintf(stderr, "Unknown value CS=0x%02X while "
983 "detecting personality of process "
984 "PID=%d\n", (int)val, pid);
985 currpers = current_personality;
986 break;
987 }
988#if 0
989 /* This version analyzes the opcode of a syscall instruction.
990 * (int 0x80 on i386 vs. syscall on x86-64)
991 * It works, but is too complicated.
992 */
993 unsigned long val, rip, i;
994
995 if(upeek(pid, 8*RIP, &rip)<0)
996 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000997
Michal Ludvig0e035502002-09-23 15:41:01 +0000998 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
999 rip-=2;
1000 errno = 0;
1001
Roland McGrath761b5d72002-12-15 23:58:31 +00001002 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
1003 if (errno)
1004 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +00001005 strerror(errno));
1006 switch (call & 0xffff)
1007 {
1008 /* x86-64: syscall = 0x0f 0x05 */
1009 case 0x050f: currpers = 0; break;
1010 /* i386: int 0x80 = 0xcd 0x80 */
1011 case 0x80cd: currpers = 1; break;
1012 default:
1013 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +00001014 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +00001015 "Unknown syscall opcode (0x%04X) while "
1016 "detecting personality of process "
1017 "PID=%d\n", (int)call, pid);
1018 break;
1019 }
1020#endif
1021 if(currpers != current_personality)
1022 {
1023 char *names[]={"64 bit", "32 bit"};
1024 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +00001025 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +00001026 pid, names[current_personality]);
1027 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001028 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001029#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001030# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001031 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001032 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001033 if (!(tcp->flags & TCB_INSYSCALL)) {
1034 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001035 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001036 return -1;
1037 } else {
1038 if (upeek (pid, PT_R15, &scno) < 0)
1039 return -1;
1040 }
Roland McGrathba954762003-03-05 06:29:06 +00001041 /* Check if we return from execve. */
1042 if (tcp->flags & TCB_WAITEXECVE) {
1043 tcp->flags &= ~TCB_WAITEXECVE;
1044 return 0;
1045 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001046 } else {
1047 /* syscall in progress */
1048 if (upeek (pid, PT_R8, &r8) < 0)
1049 return -1;
1050 if (upeek (pid, PT_R10, &r10) < 0)
1051 return -1;
1052 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001054 /*
1055 * Read complete register set in one go.
1056 */
1057 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1058 return -1;
1059
1060 /*
1061 * We only need to grab the syscall number on syscall entry.
1062 */
1063 if (regs.ARM_ip == 0) {
1064 /*
1065 * Note: we only deal with only 32-bit CPUs here.
1066 */
1067 if (regs.ARM_cpsr & 0x20) {
1068 /*
1069 * Get the Thumb-mode system call number
1070 */
1071 scno = regs.ARM_r7;
1072 } else {
1073 /*
1074 * Get the ARM-mode system call number
1075 */
1076 errno = 0;
1077 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1078 if (errno)
1079 return -1;
1080
1081 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1082 tcp->flags &= ~TCB_WAITEXECVE;
1083 return 0;
1084 }
1085
1086 if ((scno & 0x0ff00000) != 0x0f900000) {
1087 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1088 scno);
1089 return -1;
1090 }
1091
1092 /*
1093 * Fixup the syscall number
1094 */
1095 scno &= 0x000fffff;
1096 }
1097
1098 if (tcp->flags & TCB_INSYSCALL) {
1099 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1100 tcp->flags &= ~TCB_INSYSCALL;
1101 }
1102 } else {
1103 if (!(tcp->flags & TCB_INSYSCALL)) {
1104 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1105 tcp->flags |= TCB_INSYSCALL;
1106 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001107 }
1108#elif defined (M68K)
1109 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1110 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001111#elif defined (MIPS)
1112 if (upeek(pid, REG_A3, &a3) < 0)
1113 return -1;
1114
1115 if(!(tcp->flags & TCB_INSYSCALL)) {
1116 if (upeek(pid, REG_V0, &scno) < 0)
1117 return -1;
1118
1119 if (scno < 0 || scno > nsyscalls) {
1120 if(a3 == 0 || a3 == -1) {
1121 if(debug)
1122 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1123 return 0;
1124 }
1125 }
1126 } else {
1127 if (upeek(pid, REG_V0, &r2) < 0)
1128 return -1;
1129 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130#elif defined (ALPHA)
1131 if (upeek(pid, REG_A3, &a3) < 0)
1132 return -1;
1133
1134 if (!(tcp->flags & TCB_INSYSCALL)) {
1135 if (upeek(pid, REG_R0, &scno) < 0)
1136 return -1;
1137
1138 /* Check if we return from execve. */
1139 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1140 tcp->flags &= ~TCB_WAITEXECVE;
1141 return 0;
1142 }
1143
1144 /*
1145 * Do some sanity checks to figure out if it's
1146 * really a syscall entry
1147 */
1148 if (scno < 0 || scno > nsyscalls) {
1149 if (a3 == 0 || a3 == -1) {
1150 if (debug)
1151 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1152 return 0;
1153 }
1154 }
1155 }
1156 else {
1157 if (upeek(pid, REG_R0, &r0) < 0)
1158 return -1;
1159 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001160#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 /* Everything we need is in the current register set. */
1162 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1163 return -1;
1164
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 /* If we are entering, then disassemble the syscall trap. */
1166 if (!(tcp->flags & TCB_INSYSCALL)) {
1167 /* Retrieve the syscall trap instruction. */
1168 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001169 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001170#if defined(SPARC64)
1171 trap >>= 32;
1172#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 if (errno)
1174 return -1;
1175
1176 /* Disassemble the trap to see what personality to use. */
1177 switch (trap) {
1178 case 0x91d02010:
1179 /* Linux/SPARC syscall trap. */
1180 set_personality(0);
1181 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001182 case 0x91d0206d:
1183 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001184 set_personality(2);
1185 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 case 0x91d02000:
1187 /* SunOS syscall trap. (pers 1) */
1188 fprintf(stderr,"syscall: SunOS no support\n");
1189 return -1;
1190 case 0x91d02008:
1191 /* Solaris 2.x syscall trap. (per 2) */
1192 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001193 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194 case 0x91d02009:
1195 /* NetBSD/FreeBSD syscall trap. */
1196 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1197 return -1;
1198 case 0x91d02027:
1199 /* Solaris 2.x gettimeofday */
1200 set_personality(1);
1201 break;
1202 default:
1203 /* Unknown syscall trap. */
1204 if(tcp->flags & TCB_WAITEXECVE) {
1205 tcp->flags &= ~TCB_WAITEXECVE;
1206 return 0;
1207 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001208#if defined (SPARC64)
1209 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1210#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001211 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001212#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001213 return -1;
1214 }
1215
1216 /* Extract the system call number from the registers. */
1217 if (trap == 0x91d02027)
1218 scno = 156;
1219 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001220 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001222 scno = regs.r_o0;
1223 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 }
1225 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001226#elif defined(HPPA)
1227 if (upeek(pid, PT_GR20, &scno) < 0)
1228 return -1;
1229 if (!(tcp->flags & TCB_INSYSCALL)) {
1230 /* Check if we return from execve. */
1231 if ((tcp->flags & TCB_WAITEXECVE)) {
1232 tcp->flags &= ~TCB_WAITEXECVE;
1233 return 0;
1234 }
1235 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001236#elif defined(SH)
1237 /*
1238 * In the new syscall ABI, the system call number is in R3.
1239 */
1240 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1241 return -1;
1242
1243 if (scno < 0) {
1244 /* Odd as it may seem, a glibc bug has been known to cause
1245 glibc to issue bogus negative syscall numbers. So for
1246 our purposes, make strace print what it *should* have been */
1247 long correct_scno = (scno & 0xff);
1248 if (debug)
1249 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001250 "Detected glibc bug: bogus system call number = %ld, "
1251 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001252 scno,
1253 correct_scno);
1254 scno = correct_scno;
1255 }
1256
1257
1258 if (!(tcp->flags & TCB_INSYSCALL)) {
1259 /* Check if we return from execve. */
1260 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1261 tcp->flags &= ~TCB_WAITEXECVE;
1262 return 0;
1263 }
1264 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001265#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001266 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1267 return -1;
1268 scno &= 0xFFFF;
1269
1270 if (!(tcp->flags & TCB_INSYSCALL)) {
1271 /* Check if we return from execve. */
1272 if (tcp->flags & TCB_WAITEXECVE) {
1273 tcp->flags &= ~TCB_WAITEXECVE;
1274 return 0;
1275 }
1276 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001277#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278#endif /* LINUX */
1279#ifdef SUNOS4
1280 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1281 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001282#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001283 /* new syscall ABI returns result in R0 */
1284 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1285 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001286#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001287 /* ABI defines result returned in r9 */
1288 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1289 return -1;
1290
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001294 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001296#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001297 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001298#else /* FREEBSD */
1299 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1300 perror("pread");
1301 return -1;
1302 }
1303 switch (regs.r_eax) {
1304 case SYS_syscall:
1305 case SYS___syscall:
1306 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1307 break;
1308 default:
1309 scno = regs.r_eax;
1310 break;
1311 }
1312#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001314#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001315 if (!(tcp->flags & TCB_INSYSCALL))
1316 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001317 return 1;
1318}
1319
Pavel Machek4dc3b142000-02-01 17:58:41 +00001320
Roland McGrath17352792005-06-07 23:21:26 +00001321long
1322known_scno(tcp)
1323struct tcb *tcp;
1324{
1325 long scno = tcp->scno;
1326 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1327 scno = sysent[scno].native_scno;
1328 else
1329 scno += NR_SYSCALL_BASE;
1330 return scno;
1331}
1332
Roland McGratha4d48532005-06-08 20:45:28 +00001333static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001334syscall_fixup(tcp)
1335struct tcb *tcp;
1336{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001337#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001338 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001339#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001340 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001341
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001342 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001343 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001344 if (
1345 scno == SYS_fork
1346#ifdef SYS_vfork
1347 || scno == SYS_vfork
1348#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001349#ifdef SYS_fork1
1350 || scno == SYS_fork1
1351#endif /* SYS_fork1 */
1352#ifdef SYS_forkall
1353 || scno == SYS_forkall
1354#endif /* SYS_forkall */
1355#ifdef SYS_rfork1
1356 || scno == SYS_rfork1
1357#endif /* SYS_fork1 */
1358#ifdef SYS_rforkall
1359 || scno == SYS_rforkall
1360#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361 ) {
1362 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001363 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001364 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001365 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 }
1367 else {
1368 fprintf(stderr, "syscall: missing entry\n");
1369 tcp->flags |= TCB_INSYSCALL;
1370 }
1371 }
1372 }
1373 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001374 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 fprintf(stderr, "syscall: missing exit\n");
1376 tcp->flags &= ~TCB_INSYSCALL;
1377 }
1378 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001379#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001380#ifdef SUNOS4
1381 if (!(tcp->flags & TCB_INSYSCALL)) {
1382 if (scno == 0) {
1383 fprintf(stderr, "syscall: missing entry\n");
1384 tcp->flags |= TCB_INSYSCALL;
1385 }
1386 }
1387 else {
1388 if (scno != 0) {
1389 if (debug) {
1390 /*
1391 * This happens when a signal handler
1392 * for a signal which interrupted a
1393 * a system call makes another system call.
1394 */
1395 fprintf(stderr, "syscall: missing exit\n");
1396 }
1397 tcp->flags &= ~TCB_INSYSCALL;
1398 }
1399 }
1400#endif /* SUNOS4 */
1401#ifdef LINUX
1402#if defined (I386)
1403 if (upeek(pid, 4*EAX, &eax) < 0)
1404 return -1;
1405 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1406 if (debug)
1407 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1408 return 0;
1409 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001410#elif defined (X86_64)
1411 if (upeek(pid, 8*RAX, &rax) < 0)
1412 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001413 if (current_personality == 1)
1414 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001415 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1416 if (debug)
1417 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1418 return 0;
1419 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001420#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001421 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1422 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001423 if (syscall_mode != -ENOSYS)
1424 syscall_mode = tcp->scno;
1425 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001426 if (debug)
1427 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1428 return 0;
1429 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001430 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1431 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1432 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1433 /*
1434 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1435 * flag set for the post-execve SIGTRAP to see and reset.
1436 */
1437 gpr2 = 0;
1438 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001439#elif defined (POWERPC)
1440# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001441 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001442 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001443 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001444 return -1;
1445 if (flags & SO_MASK)
1446 result = -result;
1447#elif defined (M68K)
1448 if (upeek(pid, 4*PT_D0, &d0) < 0)
1449 return -1;
1450 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1451 if (debug)
1452 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1453 return 0;
1454 }
1455#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001456 /*
1457 * Nothing required
1458 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001459#elif defined (HPPA)
1460 if (upeek(pid, PT_GR28, &r28) < 0)
1461 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001462#elif defined(IA64)
1463 if (upeek(pid, PT_R10, &r10) < 0)
1464 return -1;
1465 if (upeek(pid, PT_R8, &r8) < 0)
1466 return -1;
1467 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1468 if (debug)
1469 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1470 return 0;
1471 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472#endif
1473#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001474 return 1;
1475}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476
Roland McGratha4d48532005-06-08 20:45:28 +00001477static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001478get_error(tcp)
1479struct tcb *tcp;
1480{
1481 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001483#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001484 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1485 tcp->u_rval = -1;
1486 u_error = -gpr2;
1487 }
1488 else {
1489 tcp->u_rval = gpr2;
1490 u_error = 0;
1491 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001492#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493#ifdef I386
1494 if (eax < 0 && -eax < nerrnos) {
1495 tcp->u_rval = -1;
1496 u_error = -eax;
1497 }
1498 else {
1499 tcp->u_rval = eax;
1500 u_error = 0;
1501 }
1502#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001503#ifdef X86_64
1504 if (rax < 0 && -rax < nerrnos) {
1505 tcp->u_rval = -1;
1506 u_error = -rax;
1507 }
1508 else {
1509 tcp->u_rval = rax;
1510 u_error = 0;
1511 }
1512#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001513#ifdef IA64
1514 if (ia32) {
1515 int err;
1516
1517 err = (int)r8;
1518 if (err < 0 && -err < nerrnos) {
1519 tcp->u_rval = -1;
1520 u_error = -err;
1521 }
1522 else {
1523 tcp->u_rval = err;
1524 u_error = 0;
1525 }
1526 } else {
1527 if (r10) {
1528 tcp->u_rval = -1;
1529 u_error = r8;
1530 } else {
1531 tcp->u_rval = r8;
1532 u_error = 0;
1533 }
1534 }
1535#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001536#ifdef MIPS
1537 if (a3) {
1538 tcp->u_rval = -1;
1539 u_error = r2;
1540 } else {
1541 tcp->u_rval = r2;
1542 u_error = 0;
1543 }
1544#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001546 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 tcp->u_rval = -1;
1548 u_error = -result;
1549 }
1550 else {
1551 tcp->u_rval = result;
1552 u_error = 0;
1553 }
1554#else /* !POWERPC */
1555#ifdef M68K
1556 if (d0 && (unsigned) -d0 < nerrnos) {
1557 tcp->u_rval = -1;
1558 u_error = -d0;
1559 }
1560 else {
1561 tcp->u_rval = d0;
1562 u_error = 0;
1563 }
1564#else /* !M68K */
1565#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001566 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001567 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001568 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001569 }
1570 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001571 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001572 u_error = 0;
1573 }
1574#else /* !ARM */
1575#ifdef ALPHA
1576 if (a3) {
1577 tcp->u_rval = -1;
1578 u_error = r0;
1579 }
1580 else {
1581 tcp->u_rval = r0;
1582 u_error = 0;
1583 }
1584#else /* !ALPHA */
1585#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001586 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001588 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 }
1590 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001591 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 u_error = 0;
1593 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001594#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001595#ifdef SPARC64
1596 if (regs.r_tstate & 0x1100000000UL) {
1597 tcp->u_rval = -1;
1598 u_error = regs.r_o0;
1599 }
1600 else {
1601 tcp->u_rval = regs.r_o0;
1602 u_error = 0;
1603 }
1604#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001605#ifdef HPPA
1606 if (r28 && (unsigned) -r28 < nerrnos) {
1607 tcp->u_rval = -1;
1608 u_error = -r28;
1609 }
1610 else {
1611 tcp->u_rval = r28;
1612 u_error = 0;
1613 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001614#else
1615#ifdef SH
1616 /* interpret R0 as return value or error number */
1617 if (r0 && (unsigned) -r0 < nerrnos) {
1618 tcp->u_rval = -1;
1619 u_error = -r0;
1620 }
1621 else {
1622 tcp->u_rval = r0;
1623 u_error = 0;
1624 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001625#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001626#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001627 /* interpret result as return value or error number */
1628 if (r9 && (unsigned) -r9 < nerrnos) {
1629 tcp->u_rval = -1;
1630 u_error = -r9;
1631 }
1632 else {
1633 tcp->u_rval = r9;
1634 u_error = 0;
1635 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001636#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001637#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001638#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001640#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641#endif /* ALPHA */
1642#endif /* ARM */
1643#endif /* M68K */
1644#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001645#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001646#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001647#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001649#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650#endif /* LINUX */
1651#ifdef SUNOS4
1652 /* get error code from user struct */
1653 if (upeek(pid, uoff(u_error), &u_error) < 0)
1654 return -1;
1655 u_error >>= 24; /* u_error is a char */
1656
1657 /* get system call return value */
1658 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1659 return -1;
1660#endif /* SUNOS4 */
1661#ifdef SVR4
1662#ifdef SPARC
1663 /* Judicious guessing goes a long way. */
1664 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1665 tcp->u_rval = -1;
1666 u_error = tcp->status.pr_reg[R_O0];
1667 }
1668 else {
1669 tcp->u_rval = tcp->status.pr_reg[R_O0];
1670 u_error = 0;
1671 }
1672#endif /* SPARC */
1673#ifdef I386
1674 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001675 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001677 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678 }
1679 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001680 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001681#ifdef HAVE_LONG_LONG
1682 tcp->u_lrval =
1683 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1684 tcp->status.PR_REG[EAX];
1685#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686 u_error = 0;
1687 }
1688#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001689#ifdef X86_64
1690 /* Wanna know how to kill an hour single-stepping? */
1691 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1692 tcp->u_rval = -1;
1693 u_error = tcp->status.PR_REG[RAX];
1694 }
1695 else {
1696 tcp->u_rval = tcp->status.PR_REG[RAX];
1697 u_error = 0;
1698 }
1699#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700#ifdef MIPS
1701 if (tcp->status.pr_reg[CTX_A3]) {
1702 tcp->u_rval = -1;
1703 u_error = tcp->status.pr_reg[CTX_V0];
1704 }
1705 else {
1706 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1707 u_error = 0;
1708 }
1709#endif /* MIPS */
1710#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001711#ifdef FREEBSD
1712 if (regs.r_eflags & PSL_C) {
1713 tcp->u_rval = -1;
1714 u_error = regs.r_eax;
1715 } else {
1716 tcp->u_rval = regs.r_eax;
1717 tcp->u_lrval =
1718 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1719 u_error = 0;
1720 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001721#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001722 tcp->u_error = u_error;
1723 return 1;
1724}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001725
Roland McGrathb69f81b2002-12-21 23:25:18 +00001726int
1727force_result(tcp, error, rval)
1728 struct tcb *tcp;
1729 int error;
1730 long rval;
1731{
1732#ifdef LINUX
1733#if defined(S390) || defined(S390X)
1734 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001735 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1736 return -1;
1737#else /* !S390 && !S390X */
1738#ifdef I386
1739 eax = error ? -error : rval;
1740 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1741 return -1;
1742#else /* !I386 */
1743#ifdef X86_64
1744 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001745 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001746 return -1;
1747#else
1748#ifdef IA64
1749 if (ia32) {
1750 r8 = error ? -error : rval;
1751 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1752 return -1;
1753 }
1754 else {
1755 if (error) {
1756 r8 = error;
1757 r10 = -1;
1758 }
1759 else {
1760 r8 = rval;
1761 r10 = 0;
1762 }
1763 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1764 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1765 return -1;
1766 }
1767#else /* !IA64 */
1768#ifdef MIPS
1769 if (error) {
1770 r2 = error;
1771 a3 = -1;
1772 }
1773 else {
1774 r2 = rval;
1775 a3 = 0;
1776 }
1777 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1778 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1779 return -1;
1780#else
1781#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001782 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001783 return -1;
1784 if (error) {
1785 flags |= SO_MASK;
1786 result = error;
1787 }
1788 else {
1789 flags &= ~SO_MASK;
1790 result = rval;
1791 }
Roland McGratheb285352003-01-14 09:59:00 +00001792 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1793 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 return -1;
1795#else /* !POWERPC */
1796#ifdef M68K
1797 d0 = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1799 return -1;
1800#else /* !M68K */
1801#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001802 regs.ARM_r0 = error ? -error : rval;
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001804 return -1;
1805#else /* !ARM */
1806#ifdef ALPHA
1807 if (error) {
1808 a3 = -1;
1809 r0 = error;
1810 }
1811 else {
1812 a3 = 0;
1813 r0 = rval;
1814 }
1815 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1816 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1817 return -1;
1818#else /* !ALPHA */
1819#ifdef SPARC
1820 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1821 return -1;
1822 if (error) {
1823 regs.r_psr |= PSR_C;
1824 regs.r_o0 = error;
1825 }
1826 else {
1827 regs.r_psr &= ~PSR_C;
1828 regs.r_o0 = rval;
1829 }
1830 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1831 return -1;
1832#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001833#ifdef SPARC64
1834 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1835 return -1;
1836 if (error) {
1837 regs.r_tstate |= 0x1100000000UL;
1838 regs.r_o0 = error;
1839 }
1840 else {
1841 regs.r_tstate &= ~0x1100000000UL;
1842 regs.r_o0 = rval;
1843 }
1844 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1845 return -1;
1846#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847#ifdef HPPA
1848 r28 = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1850 return -1;
1851#else
1852#ifdef SH
1853 r0 = error ? -error : rval;
1854 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1855 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001856#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001857#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001858 r9 = error ? -error : rval;
1859 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1860 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001861#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001862#endif /* SH */
1863#endif /* HPPA */
1864#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001865#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001866#endif /* ALPHA */
1867#endif /* ARM */
1868#endif /* M68K */
1869#endif /* POWERPC */
1870#endif /* MIPS */
1871#endif /* IA64 */
1872#endif /* X86_64 */
1873#endif /* I386 */
1874#endif /* S390 || S390X */
1875#endif /* LINUX */
1876#ifdef SUNOS4
1877 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1878 error << 24) < 0 ||
1879 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1880 return -1;
1881#endif /* SUNOS4 */
1882#ifdef SVR4
1883 /* XXX no clue */
1884 return -1;
1885#endif /* SVR4 */
1886#ifdef FREEBSD
1887 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1888 perror("pread");
1889 return -1;
1890 }
1891 if (error) {
1892 regs.r_eflags |= PSL_C;
1893 regs.r_eax = error;
1894 }
1895 else {
1896 regs.r_eflags &= ~PSL_C;
1897 regs.r_eax = rval;
1898 }
1899 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1900 perror("pwrite");
1901 return -1;
1902 }
1903#endif /* FREEBSD */
1904
1905 /* All branches reach here on success (only). */
1906 tcp->u_error = error;
1907 tcp->u_rval = rval;
1908 return 0;
1909}
1910
Roland McGratha4d48532005-06-08 20:45:28 +00001911static int
1912syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001913struct tcb *tcp;
1914{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001915#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001916 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001917#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001918#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001919#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001920 {
1921 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001922 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1923 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001924 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001925 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001926 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001927 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001928 return -1;
1929 }
1930 }
1931#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001932 {
1933 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001934 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1935 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001936 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001937 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001938 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001939 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1940 * for scno somewhere above here!
1941 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001942 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1943 return -1;
1944 }
1945 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001946#elif defined (IA64)
1947 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001948 if (!ia32) {
1949 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1950 /* be backwards compatible with kernel < 2.4.4... */
1951# ifndef PT_RBS_END
1952# define PT_RBS_END PT_AR_BSP
1953# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001954
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001955 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001956 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001957 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1958 return -1;
1959
1960 sof = (cfm >> 0) & 0x7f;
1961 sol = (cfm >> 7) & 0x7f;
1962 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1963
1964 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1965 && sysent[tcp->scno].nargs != -1)
1966 tcp->u_nargs = sysent[tcp->scno].nargs;
1967 else
1968 tcp->u_nargs = MAX_ARGS;
1969 for (i = 0; i < tcp->u_nargs; ++i) {
1970 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1971 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1972 return -1;
1973 }
1974 } else {
1975 int i;
1976
1977 if (/* EBX = out0 */
1978 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1979 /* ECX = out1 */
1980 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1981 /* EDX = out2 */
1982 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1983 /* ESI = out3 */
1984 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1985 /* EDI = out4 */
1986 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1987 /* EBP = out5 */
1988 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1989 return -1;
1990
1991 for (i = 0; i < 6; ++i)
1992 /* truncate away IVE sign-extension */
1993 tcp->u_arg[i] &= 0xffffffff;
1994
1995 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1996 && sysent[tcp->scno].nargs != -1)
1997 tcp->u_nargs = sysent[tcp->scno].nargs;
1998 else
1999 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002000 }
2001 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002002#elif defined (MIPS)
2003 {
2004 long sp;
2005 int i, nargs;
2006
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002007 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2008 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002009 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002010 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002011 if(nargs > 4) {
2012 if(upeek(pid, REG_SP, &sp) < 0)
2013 return -1;
2014 for(i = 0; i < 4; i++) {
2015 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2016 return -1;
2017 }
2018 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2019 (char *)(tcp->u_arg + 4));
2020 } else {
2021 for(i = 0; i < nargs; i++) {
2022 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2023 return -1;
2024 }
2025 }
2026 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002027#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002028#ifndef PT_ORIG_R3
2029#define PT_ORIG_R3 34
2030#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 {
2032 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002033 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2034 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002035 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002036 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002037 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002038 if (upeek(pid, (i==0) ?
2039 (sizeof(unsigned long)*PT_ORIG_R3) :
2040 ((i+PT_R3)*sizeof(unsigned long)),
2041 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002042 return -1;
2043 }
2044 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002045#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002046 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002047 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002048
2049 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2050 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002051 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002052 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002053 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002054 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002055 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002056#elif defined (HPPA)
2057 {
2058 int i;
2059
2060 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2061 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002062 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002063 tcp->u_nargs = MAX_ARGS;
2064 for (i = 0; i < tcp->u_nargs; i++) {
2065 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2066 return -1;
2067 }
2068 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002069#elif defined(ARM)
2070 {
2071 int i;
2072
2073 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2074 tcp->u_nargs = sysent[tcp->scno].nargs;
2075 else
2076 tcp->u_nargs = MAX_ARGS;
2077 for (i = 0; i < tcp->u_nargs; i++)
2078 tcp->u_arg[i] = regs.uregs[i];
2079 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002080#elif defined(SH)
2081 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002082 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002083 static int syscall_regs[] = {
2084 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2085 REG_REG0, REG_REG0+1, REG_REG0+2
2086 };
2087
2088 tcp->u_nargs = sysent[tcp->scno].nargs;
2089 for (i = 0; i < tcp->u_nargs; i++) {
2090 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2091 return -1;
2092 }
2093 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002094#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002095 {
2096 int i;
2097 /* Registers used by SH5 Linux system calls for parameters */
2098 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2099
2100 /*
2101 * TODO: should also check that the number of arguments encoded
2102 * in the trap number matches the number strace expects.
2103 */
2104 /*
2105 assert(sysent[tcp->scno].nargs <
2106 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2107 */
2108
2109 tcp->u_nargs = sysent[tcp->scno].nargs;
2110 for (i = 0; i < tcp->u_nargs; i++) {
2111 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2112 return -1;
2113 }
2114 }
2115
Michal Ludvig0e035502002-09-23 15:41:01 +00002116#elif defined(X86_64)
2117 {
2118 int i;
2119 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2120 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002121 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002122 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002123
Michal Ludvig0e035502002-09-23 15:41:01 +00002124 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2125 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002126 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002127 tcp->u_nargs = MAX_ARGS;
2128 for (i = 0; i < tcp->u_nargs; i++) {
2129 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2130 return -1;
2131 }
2132 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002133#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 {
2135 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002136 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002138 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002139 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002140 for (i = 0; i < tcp->u_nargs; i++) {
2141 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2142 return -1;
2143 }
2144 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002145#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002146#endif /* LINUX */
2147#ifdef SUNOS4
2148 {
2149 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002150 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2151 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002152 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002153 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002154 for (i = 0; i < tcp->u_nargs; i++) {
2155 struct user *u;
2156
2157 if (upeek(pid, uoff(u_arg[0]) +
2158 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2159 return -1;
2160 }
2161 }
2162#endif /* SUNOS4 */
2163#ifdef SVR4
2164#ifdef MIPS
2165 /*
2166 * SGI is broken: even though it has pr_sysarg, it doesn't
2167 * set them on system call entry. Get a clue.
2168 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002169 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002170 tcp->u_nargs = sysent[tcp->scno].nargs;
2171 else
2172 tcp->u_nargs = tcp->status.pr_nsysarg;
2173 if (tcp->u_nargs > 4) {
2174 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2175 4*sizeof(tcp->u_arg[0]));
2176 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2177 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2178 }
2179 else {
2180 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2181 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2182 }
John Hughes25299712001-03-06 10:10:06 +00002183#elif UNIXWARE >= 2
2184 /*
2185 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2186 */
2187 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2188 tcp->u_nargs = sysent[tcp->scno].nargs;
2189 else
2190 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2191 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2192 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2193#elif defined (HAVE_PR_SYSCALL)
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 {
2199 int i;
2200 for (i = 0; i < tcp->u_nargs; i++)
2201 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2202 }
John Hughes25299712001-03-06 10:10:06 +00002203#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002204 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002205 tcp->u_nargs = sysent[tcp->scno].nargs;
2206 else
2207 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002208 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002209 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002210#else
2211 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002213#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002214#ifdef FREEBSD
2215 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2216 sysent[tcp->scno].nargs > tcp->status.val)
2217 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002218 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002219 tcp->u_nargs = tcp->status.val;
2220 if (tcp->u_nargs < 0)
2221 tcp->u_nargs = 0;
2222 if (tcp->u_nargs > MAX_ARGS)
2223 tcp->u_nargs = MAX_ARGS;
2224 switch(regs.r_eax) {
2225 case SYS___syscall:
2226 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2227 regs.r_esp + sizeof(int) + sizeof(quad_t));
2228 break;
2229 case SYS_syscall:
2230 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2231 regs.r_esp + 2 * sizeof(int));
2232 break;
2233 default:
2234 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2235 regs.r_esp + sizeof(int));
2236 break;
2237 }
2238#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002239 return 1;
2240}
2241
2242int
2243trace_syscall(tcp)
2244struct tcb *tcp;
2245{
2246 int sys_res;
2247 struct timeval tv;
2248 int res;
2249
2250 /* Measure the exit time as early as possible to avoid errors. */
2251 if (dtime && (tcp->flags & TCB_INSYSCALL))
2252 gettimeofday(&tv, NULL);
2253
2254 res = get_scno(tcp);
2255 if (res != 1)
2256 return res;
2257
2258 res = syscall_fixup(tcp);
2259 if (res != 1)
2260 return res;
2261
2262 if (tcp->flags & TCB_INSYSCALL) {
2263 long u_error;
2264 res = get_error(tcp);
2265 if (res != 1)
2266 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002267
2268 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002269 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2270 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002271 tcp->flags &= ~TCB_INSYSCALL;
2272 return 0;
2273 }
2274
2275 if (tcp->flags & TCB_REPRINT) {
2276 printleader(tcp);
2277 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002278 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002279 tprintf("syscall_%lu", tcp->scno);
2280 else
2281 tprintf("%s", sysent[tcp->scno].sys_name);
2282 tprintf(" resumed> ");
2283 }
2284
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002285 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002286 if (counts == NULL) {
2287 counts = calloc(sizeof *counts, nsyscalls);
2288 if (counts == NULL) {
2289 fprintf(stderr, "\
2290strace: out of memory for call counts\n");
2291 exit(1);
2292 }
2293 }
2294
2295 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002296 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002297 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002298 tv_sub(&tv, &tv, &tcp->etime);
2299#ifdef LINUX
2300 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002301 static struct timeval one_tick;
2302 if (one_tick.tv_usec == 0) {
2303 /* Initialize it. */
2304 struct itimerval it;
2305 memset(&it, 0, sizeof it);
2306 it.it_interval.tv_usec = 1;
2307 setitimer(ITIMER_REAL, &it, NULL);
2308 getitimer(ITIMER_REAL, &it);
2309 one_tick = it.it_interval;
2310 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002311
2312 if (tv_nz(&tcp->dtime))
2313 tv = tcp->dtime;
2314 else if (tv_cmp(&tv, &one_tick) > 0) {
2315 if (tv_cmp(&shortest, &one_tick) < 0)
2316 tv = shortest;
2317 else
2318 tv = one_tick;
2319 }
2320 }
2321#endif /* LINUX */
2322 if (tv_cmp(&tv, &shortest) < 0)
2323 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002324 tv_add(&counts[tcp->scno].time,
2325 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002326 tcp->flags &= ~TCB_INSYSCALL;
2327 return 0;
2328 }
2329
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002330 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331 || (qual_flags[tcp->scno] & QUAL_RAW))
2332 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002333 else {
2334 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002335 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002337 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338 u_error = tcp->u_error;
2339 tprintf(") ");
2340 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002341 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2342 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002343 if (u_error)
2344 tprintf("= -1 (errno %ld)", u_error);
2345 else
2346 tprintf("= %#lx", tcp->u_rval);
2347 }
2348 else if (!(sys_res & RVAL_NONE) && u_error) {
2349 switch (u_error) {
2350#ifdef LINUX
2351 case ERESTARTSYS:
2352 tprintf("= ? ERESTARTSYS (To be restarted)");
2353 break;
2354 case ERESTARTNOINTR:
2355 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2356 break;
2357 case ERESTARTNOHAND:
2358 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2359 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002360 case ERESTART_RESTARTBLOCK:
2361 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2362 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002363#endif /* LINUX */
2364 default:
2365 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002366 if (u_error < 0)
2367 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002368 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002369 tprintf("%s (%s)", errnoent[u_error],
2370 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002371 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002372 tprintf("ERRNO_%ld (%s)", u_error,
2373 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002374 break;
2375 }
2376 }
2377 else {
2378 if (sys_res & RVAL_NONE)
2379 tprintf("= ?");
2380 else {
2381 switch (sys_res & RVAL_MASK) {
2382 case RVAL_HEX:
2383 tprintf("= %#lx", tcp->u_rval);
2384 break;
2385 case RVAL_OCTAL:
2386 tprintf("= %#lo", tcp->u_rval);
2387 break;
2388 case RVAL_UDECIMAL:
2389 tprintf("= %lu", tcp->u_rval);
2390 break;
2391 case RVAL_DECIMAL:
2392 tprintf("= %ld", tcp->u_rval);
2393 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002394#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002395 case RVAL_LHEX:
2396 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002397 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002398 case RVAL_LOCTAL:
2399 tprintf("= %#llo", tcp->u_lrval);
2400 break;
2401 case RVAL_LUDECIMAL:
2402 tprintf("= %llu", tcp->u_lrval);
2403 break;
2404 case RVAL_LDECIMAL:
2405 tprintf("= %lld", tcp->u_lrval);
2406 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002407#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002408 default:
2409 fprintf(stderr,
2410 "invalid rval format\n");
2411 break;
2412 }
2413 }
2414 if ((sys_res & RVAL_STR) && tcp->auxstr)
2415 tprintf(" (%s)", tcp->auxstr);
2416 }
2417 if (dtime) {
2418 tv_sub(&tv, &tv, &tcp->etime);
2419 tprintf(" <%ld.%06ld>",
2420 (long) tv.tv_sec, (long) tv.tv_usec);
2421 }
2422 printtrailer(tcp);
2423
2424 dumpio(tcp);
2425 if (fflush(tcp->outf) == EOF)
2426 return -1;
2427 tcp->flags &= ~TCB_INSYSCALL;
2428 return 0;
2429 }
2430
2431 /* Entering system call */
2432 res = syscall_enter(tcp);
2433 if (res != 1)
2434 return res;
2435
Roland McGrath17352792005-06-07 23:21:26 +00002436 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002437#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002438#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002439 case SYS_socketcall:
2440 decode_subcall(tcp, SYS_socket_subcall,
2441 SYS_socket_nsubcalls, deref_style);
2442 break;
2443 case SYS_ipc:
2444 decode_subcall(tcp, SYS_ipc_subcall,
2445 SYS_ipc_nsubcalls, shift_style);
2446 break;
Roland McGrath17352792005-06-07 23:21:26 +00002447#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002448#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002449 case SYS_socketcall:
2450 sparc_socket_decode (tcp);
2451 break;
2452#endif
2453#endif /* LINUX */
2454#ifdef SVR4
2455#ifdef SYS_pgrpsys_subcall
2456 case SYS_pgrpsys:
2457 decode_subcall(tcp, SYS_pgrpsys_subcall,
2458 SYS_pgrpsys_nsubcalls, shift_style);
2459 break;
2460#endif /* SYS_pgrpsys_subcall */
2461#ifdef SYS_sigcall_subcall
2462 case SYS_sigcall:
2463 decode_subcall(tcp, SYS_sigcall_subcall,
2464 SYS_sigcall_nsubcalls, mask_style);
2465 break;
2466#endif /* SYS_sigcall_subcall */
2467 case SYS_msgsys:
2468 decode_subcall(tcp, SYS_msgsys_subcall,
2469 SYS_msgsys_nsubcalls, shift_style);
2470 break;
2471 case SYS_shmsys:
2472 decode_subcall(tcp, SYS_shmsys_subcall,
2473 SYS_shmsys_nsubcalls, shift_style);
2474 break;
2475 case SYS_semsys:
2476 decode_subcall(tcp, SYS_semsys_subcall,
2477 SYS_semsys_nsubcalls, shift_style);
2478 break;
2479#if 0 /* broken */
2480 case SYS_utssys:
2481 decode_subcall(tcp, SYS_utssys_subcall,
2482 SYS_utssys_nsubcalls, shift_style);
2483 break;
2484#endif
2485 case SYS_sysfs:
2486 decode_subcall(tcp, SYS_sysfs_subcall,
2487 SYS_sysfs_nsubcalls, shift_style);
2488 break;
2489 case SYS_spcall:
2490 decode_subcall(tcp, SYS_spcall_subcall,
2491 SYS_spcall_nsubcalls, shift_style);
2492 break;
2493#ifdef SYS_context_subcall
2494 case SYS_context:
2495 decode_subcall(tcp, SYS_context_subcall,
2496 SYS_context_nsubcalls, shift_style);
2497 break;
2498#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002499#ifdef SYS_door_subcall
2500 case SYS_door:
2501 decode_subcall(tcp, SYS_door_subcall,
2502 SYS_door_nsubcalls, door_style);
2503 break;
2504#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002505#ifdef SYS_kaio_subcall
2506 case SYS_kaio:
2507 decode_subcall(tcp, SYS_kaio_subcall,
2508 SYS_kaio_nsubcalls, shift_style);
2509 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002510#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002512#ifdef FREEBSD
2513 case SYS_msgsys:
2514 case SYS_shmsys:
2515 case SYS_semsys:
2516 decode_subcall(tcp, 0, 0, table_style);
2517 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002518#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002519#ifdef SUNOS4
2520 case SYS_semsys:
2521 decode_subcall(tcp, SYS_semsys_subcall,
2522 SYS_semsys_nsubcalls, shift_style);
2523 break;
2524 case SYS_msgsys:
2525 decode_subcall(tcp, SYS_msgsys_subcall,
2526 SYS_msgsys_nsubcalls, shift_style);
2527 break;
2528 case SYS_shmsys:
2529 decode_subcall(tcp, SYS_shmsys_subcall,
2530 SYS_shmsys_nsubcalls, shift_style);
2531 break;
2532#endif
2533 }
2534
2535 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002536 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 tcp->flags |= TCB_INSYSCALL;
2538 return 0;
2539 }
2540
2541 if (cflag) {
2542 gettimeofday(&tcp->etime, NULL);
2543 tcp->flags |= TCB_INSYSCALL;
2544 return 0;
2545 }
2546
2547 printleader(tcp);
2548 tcp->flags &= ~TCB_REPRINT;
2549 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002550 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002551 tprintf("syscall_%lu(", tcp->scno);
2552 else
2553 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002554 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002555 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2556 sys_res = printargs(tcp);
2557 else
2558 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2559 if (fflush(tcp->outf) == EOF)
2560 return -1;
2561 tcp->flags |= TCB_INSYSCALL;
2562 /* Measure the entrance time as late as possible to avoid errors. */
2563 if (dtime)
2564 gettimeofday(&tcp->etime, NULL);
2565 return sys_res;
2566}
2567
2568int
2569printargs(tcp)
2570struct tcb *tcp;
2571{
2572 if (entering(tcp)) {
2573 int i;
2574
2575 for (i = 0; i < tcp->u_nargs; i++)
2576 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2577 }
2578 return 0;
2579}
2580
2581long
2582getrval2(tcp)
2583struct tcb *tcp;
2584{
2585 long val = -1;
2586
2587#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002588#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002589 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2591 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002592 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002593#elif defined(SH)
2594 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2595 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002596#elif defined(IA64)
2597 if (upeek(tcp->pid, PT_R9, &val) < 0)
2598 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002599#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600#endif /* LINUX */
2601
2602#ifdef SUNOS4
2603 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2604 return -1;
2605#endif /* SUNOS4 */
2606
2607#ifdef SVR4
2608#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002609 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610#endif /* SPARC */
2611#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002612 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002613#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002614#ifdef X86_64
2615 val = tcp->status.PR_REG[RDX];
2616#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002617#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002618 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619#endif /* MIPS */
2620#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002621#ifdef FREEBSD
2622 struct reg regs;
2623 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2624 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002625#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002626 return val;
2627}
2628
2629/*
2630 * Apparently, indirect system calls have already be converted by ptrace(2),
2631 * so if you see "indir" this program has gone astray.
2632 */
2633int
2634sys_indir(tcp)
2635struct tcb *tcp;
2636{
2637 int i, scno, nargs;
2638
2639 if (entering(tcp)) {
2640 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2641 fprintf(stderr, "Bogus syscall: %u\n", scno);
2642 return 0;
2643 }
2644 nargs = sysent[scno].nargs;
2645 tprintf("%s", sysent[scno].sys_name);
2646 for (i = 0; i < nargs; i++)
2647 tprintf(", %#lx", tcp->u_arg[i+1]);
2648 }
2649 return 0;
2650}
2651
2652static int
2653time_cmp(a, b)
2654void *a;
2655void *b;
2656{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002657 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002658}
2659
2660static int
2661syscall_cmp(a, b)
2662void *a;
2663void *b;
2664{
2665 return strcmp(sysent[*((int *) a)].sys_name,
2666 sysent[*((int *) b)].sys_name);
2667}
2668
2669static int
2670count_cmp(a, b)
2671void *a;
2672void *b;
2673{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002674 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675
2676 return (m < n) ? 1 : (m > n) ? -1 : 0;
2677}
2678
2679static int (*sortfun)();
2680static struct timeval overhead = { -1, -1 };
2681
2682void
2683set_sortby(sortby)
2684char *sortby;
2685{
2686 if (strcmp(sortby, "time") == 0)
2687 sortfun = time_cmp;
2688 else if (strcmp(sortby, "calls") == 0)
2689 sortfun = count_cmp;
2690 else if (strcmp(sortby, "name") == 0)
2691 sortfun = syscall_cmp;
2692 else if (strcmp(sortby, "nothing") == 0)
2693 sortfun = NULL;
2694 else {
2695 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2696 exit(1);
2697 }
2698}
2699
2700void set_overhead(n)
2701int n;
2702{
2703 overhead.tv_sec = n / 1000000;
2704 overhead.tv_usec = n % 1000000;
2705}
2706
2707void
2708call_summary(outf)
2709FILE *outf;
2710{
2711 int i, j;
2712 int call_cum, error_cum;
2713 struct timeval tv_cum, dtv;
2714 double percent;
2715 char *dashes = "-------------------------";
2716 char error_str[16];
2717
Roland McGrathe10e62a2004-09-04 04:20:43 +00002718 int *sorted_count = malloc(nsyscalls * sizeof(int));
2719
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2721 if (overhead.tv_sec == -1) {
2722 tv_mul(&overhead, &shortest, 8);
2723 tv_div(&overhead, &overhead, 10);
2724 }
2725 for (i = 0; i < nsyscalls; i++) {
2726 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002727 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002729 tv_mul(&dtv, &overhead, counts[i].calls);
2730 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2731 call_cum += counts[i].calls;
2732 error_cum += counts[i].errors;
2733 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002735 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2737 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2738 "% time", "seconds", "usecs/call",
2739 "calls", "errors", "syscall");
2740 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2741 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002742 if (counts) {
2743 for (i = 0; i < nsyscalls; i++) {
2744 j = sorted_count[i];
2745 if (counts[j].calls == 0)
2746 continue;
2747 tv_div(&dtv, &counts[j].time, counts[j].calls);
2748 if (counts[j].errors)
2749 sprintf(error_str, "%d", counts[j].errors);
2750 else
2751 error_str[0] = '\0';
2752 percent = (100.0 * tv_float(&counts[j].time)
2753 / tv_float(&tv_cum));
2754 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2755 percent, (long) counts[j].time.tv_sec,
2756 (long) counts[j].time.tv_usec,
2757 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2758 counts[j].calls,
2759 error_str, sysent[j].sys_name);
2760 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002761 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002762 free(sorted_count);
2763
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002764 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2765 dashes, dashes, dashes, dashes, dashes, dashes);
2766 if (error_cum)
2767 sprintf(error_str, "%d", error_cum);
2768 else
2769 error_str[0] = '\0';
2770 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2771 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2772 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002773
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002774}