blob: 09a1b753cad88ffe086c6602c7e74fb2a7af861d [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. */
121#define TF TRACE_FILE
122#define TI TRACE_IPC
123#define TN TRACE_NETWORK
124#define TP TRACE_PROCESS
125#define TS TRACE_SIGNAL
126
Roland McGrathee36ce12004-09-04 03:53:10 +0000127static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128#include "syscallent.h"
129};
Roland McGrathee36ce12004-09-04 03:53:10 +0000130static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000133static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#include "syscallent1.h"
135};
Roland McGrathee36ce12004-09-04 03:53:10 +0000136static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137#endif /* SUPPORTED_PERSONALITIES >= 2 */
138
139#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000140static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#include "syscallent2.h"
142};
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#endif /* SUPPORTED_PERSONALITIES >= 3 */
145
Roland McGrathee36ce12004-09-04 03:53:10 +0000146const struct sysent *sysent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000147int nsyscalls;
148
149/* Now undef them since short defines cause wicked namespace pollution. */
150#undef TF
151#undef TI
152#undef TN
153#undef TP
154#undef TS
155
Roland McGrathee36ce12004-09-04 03:53:10 +0000156static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157#include "errnoent.h"
158};
Roland McGrathee36ce12004-09-04 03:53:10 +0000159static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160
161#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent1.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166#endif /* SUPPORTED_PERSONALITIES >= 2 */
167
168#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent2.h"
171};
Roland McGrathee36ce12004-09-04 03:53:10 +0000172static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000173#endif /* SUPPORTED_PERSONALITIES >= 3 */
174
Roland McGrathee36ce12004-09-04 03:53:10 +0000175const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176int nerrnos;
177
178int current_personality;
179
180int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000181set_personality(personality)
182int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183{
184 switch (personality) {
185 case 0:
186 errnoent = errnoent0;
187 nerrnos = nerrnos0;
188 sysent = sysent0;
189 nsyscalls = nsyscalls0;
190 ioctlent = ioctlent0;
191 nioctlents = nioctlents0;
192 signalent = signalent0;
193 nsignals = nsignals0;
194 break;
195
196#if SUPPORTED_PERSONALITIES >= 2
197 case 1:
198 errnoent = errnoent1;
199 nerrnos = nerrnos1;
200 sysent = sysent1;
201 nsyscalls = nsyscalls1;
202 ioctlent = ioctlent1;
203 nioctlents = nioctlents1;
204 signalent = signalent1;
205 nsignals = nsignals1;
206 break;
207#endif /* SUPPORTED_PERSONALITIES >= 2 */
208
209#if SUPPORTED_PERSONALITIES >= 3
210 case 2:
211 errnoent = errnoent2;
212 nerrnos = nerrnos2;
213 sysent = sysent2;
214 nsyscalls = nsyscalls2;
215 ioctlent = ioctlent2;
216 nioctlents = nioctlents2;
217 signalent = signalent2;
218 nsignals = nsignals2;
219 break;
220#endif /* SUPPORTED_PERSONALITIES >= 3 */
221
222 default:
223 return -1;
224 }
225
226 current_personality = personality;
227 return 0;
228}
229
230int qual_flags[MAX_QUALS];
231
Roland McGrathe10e62a2004-09-04 04:20:43 +0000232
233struct call_counts {
234 struct timeval time;
235 int calls, errors;
236};
237
238static struct call_counts *counts;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000239
240static struct timeval shortest = { 1000000, 0 };
241
Roland McGrath9797ceb2002-12-30 10:23:00 +0000242static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000243
Roland McGrathe10e62a2004-09-04 04:20:43 +0000244static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000245 int bitflag;
246 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000247 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000248 char *argument_name;
249} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000250 { QUAL_TRACE, "trace", qual_syscall, "system call" },
251 { QUAL_TRACE, "t", qual_syscall, "system call" },
252 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
253 { QUAL_ABBREV, "a", qual_syscall, "system call" },
254 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
255 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
256 { QUAL_RAW, "raw", qual_syscall, "system call" },
257 { QUAL_RAW, "x", qual_syscall, "system call" },
258 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
259 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
260 { QUAL_SIGNAL, "s", qual_signal, "signal" },
261 { QUAL_FAULT, "fault", qual_fault, "fault" },
262 { QUAL_FAULT, "faults", qual_fault, "fault" },
263 { QUAL_FAULT, "m", qual_fault, "fault" },
264 { QUAL_READ, "read", qual_desc, "descriptor" },
265 { QUAL_READ, "reads", qual_desc, "descriptor" },
266 { QUAL_READ, "r", qual_desc, "descriptor" },
267 { QUAL_WRITE, "write", qual_desc, "descriptor" },
268 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
269 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270 { 0, NULL, NULL, NULL },
271};
272
Roland McGrath9797ceb2002-12-30 10:23:00 +0000273static void
274qualify_one(n, opt, not)
275 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000276 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000277 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278{
Roland McGrath9797ceb2002-12-30 10:23:00 +0000279 if (not)
280 qual_flags[n] &= ~opt->bitflag;
281 else
282 qual_flags[n] |= opt->bitflag;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000283}
284
285static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000286qual_syscall(s, opt, not)
287 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000288 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000289 int not;
290{
291 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000292 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000293
294 for (i = 0; i < nsyscalls; i++) {
295 if (strcmp(s, sysent[i].sys_name) == 0) {
296 qualify_one(i, opt, not);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000297 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000298 }
299 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000300 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000301}
302
303static int
304qual_signal(s, opt, not)
305 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000306 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000307 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308{
309 int i;
310 char buf[32];
311
Roland McGrathfe6b3522005-02-02 04:40:11 +0000312 if (s && *s && isdigit((unsigned char)*s)) {
313 int signo = atoi(s);
314 if (signo < 0 || signo >= MAX_QUALS)
315 return -1;
316 qualify_one(signo, opt, not);
317 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000318 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000319 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000320 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000321 strcpy(buf, s);
322 s = buf;
323 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000324 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000325 if (strncmp(s, "SIG", 3) == 0)
326 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000327 for (i = 0; i <= NSIG; i++)
328 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath76421df2005-02-02 03:51:18 +0000329 qualify_one(i, opt, not);
330 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000331 }
Roland McGrath76421df2005-02-02 03:51:18 +0000332 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000333}
334
335static int
336qual_fault(s, opt, not)
337 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000338 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000339 int not;
340{
341 return -1;
342}
343
344static int
345qual_desc(s, opt, not)
346 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000347 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000348 int not;
349{
350 if (s && *s && isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000351 int desc = atoi(s);
352 if (desc < 0 || desc >= MAX_QUALS)
353 return -1;
354 qualify_one(desc, opt, not);
Roland McGrath2b619022003-04-10 18:58:20 +0000355 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000356 }
357 return -1;
358}
359
360static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000361lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363{
364 if (strcmp(s, "file") == 0)
365 return TRACE_FILE;
366 if (strcmp(s, "ipc") == 0)
367 return TRACE_IPC;
368 if (strcmp(s, "network") == 0)
369 return TRACE_NETWORK;
370 if (strcmp(s, "process") == 0)
371 return TRACE_PROCESS;
372 if (strcmp(s, "signal") == 0)
373 return TRACE_SIGNAL;
374 return -1;
375}
376
377void
378qualify(s)
379char *s;
380{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000381 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 int not;
383 char *p;
384 int i, n;
385
386 opt = &qual_options[0];
387 for (i = 0; (p = qual_options[i].option_name); i++) {
388 n = strlen(p);
389 if (strncmp(s, p, n) == 0 && s[n] == '=') {
390 opt = &qual_options[i];
391 s += n + 1;
392 break;
393 }
394 }
395 not = 0;
396 if (*s == '!') {
397 not = 1;
398 s++;
399 }
400 if (strcmp(s, "none") == 0) {
401 not = 1 - not;
402 s = "all";
403 }
404 if (strcmp(s, "all") == 0) {
405 for (i = 0; i < MAX_QUALS; i++) {
406 if (not)
407 qual_flags[i] &= ~opt->bitflag;
408 else
409 qual_flags[i] |= opt->bitflag;
410 }
411 return;
412 }
413 for (i = 0; i < MAX_QUALS; i++) {
414 if (not)
415 qual_flags[i] |= opt->bitflag;
416 else
417 qual_flags[i] &= ~opt->bitflag;
418 }
419 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
420 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
421 for (i = 0; i < MAX_QUALS; i++) {
422 if (sysent[i].sys_flags & n) {
423 if (not)
424 qual_flags[i] &= ~opt->bitflag;
425 else
426 qual_flags[i] |= opt->bitflag;
427 }
428 }
429 continue;
430 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000431 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000432 fprintf(stderr, "strace: invalid %s `%s'\n",
433 opt->argument_name, p);
434 exit(1);
435 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 }
437 return;
438}
439
440static void
441dumpio(tcp)
442struct tcb *tcp;
443{
444 if (syserror(tcp))
445 return;
446 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
447 return;
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000448 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000449 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000450#ifdef SYS_pread64
451 case SYS_pread64:
452#endif
453#if defined SYS_pread && SYS_pread64 != SYS_pread
454 case SYS_pread:
455#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000456#ifdef SYS_recv
457 case SYS_recv:
458#endif
459#ifdef SYS_recvfrom
460 case SYS_recvfrom:
461#endif
462 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
463 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
464 break;
465 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000466#ifdef SYS_pwrite64
467 case SYS_pwrite64:
468#endif
469#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
470 case SYS_pwrite:
471#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472#ifdef SYS_send
473 case SYS_send:
474#endif
475#ifdef SYS_sendto
476 case SYS_sendto:
477#endif
478 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
479 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
480 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000481#ifdef SYS_readv
482 case SYS_readv:
483 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
484 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
485 break;
486#endif
487#ifdef SYS_writev
488 case SYS_writev:
489
490 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
491 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
492 break;
493#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495}
496
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000497#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000498enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000499#else /* FREEBSD */
500enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
501
502struct subcall {
503 int call;
504 int nsubcalls;
505 int subcalls[5];
506};
507
508const struct subcall subcalls_table[] = {
509 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000510#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000511 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000512#else
513 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
514#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000515 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
516};
517#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000519#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520
521const int socket_map [] = {
522 /* SYS_SOCKET */ 97,
523 /* SYS_BIND */ 104,
524 /* SYS_CONNECT */ 98,
525 /* SYS_LISTEN */ 106,
526 /* SYS_ACCEPT */ 99,
527 /* SYS_GETSOCKNAME */ 150,
528 /* SYS_GETPEERNAME */ 141,
529 /* SYS_SOCKETPAIR */ 135,
530 /* SYS_SEND */ 101,
531 /* SYS_RECV */ 102,
532 /* SYS_SENDTO */ 133,
533 /* SYS_RECVFROM */ 125,
534 /* SYS_SHUTDOWN */ 134,
535 /* SYS_SETSOCKOPT */ 105,
536 /* SYS_GETSOCKOPT */ 118,
537 /* SYS_SENDMSG */ 114,
538 /* SYS_RECVMSG */ 113
539};
540
541void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000542sparc_socket_decode (tcp)
543struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544{
545 volatile long addr;
546 volatile int i, n;
547
548 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
549 return;
550 }
551 tcp->scno = socket_map [tcp->u_arg [0]-1];
552 n = tcp->u_nargs = sysent [tcp->scno].nargs;
553 addr = tcp->u_arg [1];
554 for (i = 0; i < n; i++){
555 int arg;
556 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
557 arg = 0;
558 tcp->u_arg [i] = arg;
559 addr += sizeof (arg);
560 }
561}
562
Michal Ludvig0e035502002-09-23 15:41:01 +0000563void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564decode_subcall(tcp, subcall, nsubcalls, style)
565struct tcb *tcp;
566int subcall;
567int nsubcalls;
568enum subcall_style style;
569{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000570 long addr, mask, arg;
571 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000572
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 switch (style) {
574 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000575 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
576 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 tcp->scno = subcall + tcp->u_arg[0];
578 if (sysent[tcp->scno].nargs != -1)
579 tcp->u_nargs = sysent[tcp->scno].nargs;
580 else
581 tcp->u_nargs--;
582 for (i = 0; i < tcp->u_nargs; i++)
583 tcp->u_arg[i] = tcp->u_arg[i + 1];
584 break;
585 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000586 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
587 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 tcp->scno = subcall + tcp->u_arg[0];
589 addr = tcp->u_arg[1];
590 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
591 if (umove(tcp, addr, &arg) < 0)
592 arg = 0;
593 tcp->u_arg[i] = arg;
594 addr += sizeof(arg);
595 }
596 tcp->u_nargs = sysent[tcp->scno].nargs;
597 break;
598 case mask_style:
599 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 for (i = 0; mask; i++)
601 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000602 if (i >= nsubcalls)
603 return;
604 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 tcp->scno = subcall + i;
606 if (sysent[tcp->scno].nargs != -1)
607 tcp->u_nargs = sysent[tcp->scno].nargs;
608 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000609 case door_style:
610 /*
611 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000612 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000613 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000614 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
615 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000616 tcp->scno = subcall + tcp->u_arg[5];
617 if (sysent[tcp->scno].nargs != -1)
618 tcp->u_nargs = sysent[tcp->scno].nargs;
619 else
620 tcp->u_nargs--;
621 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000622#ifdef FREEBSD
623 case table_style:
624 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
625 if (subcalls_table[i].call == tcp->scno) break;
626 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
627 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
628 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
629 for (i = 0; i < tcp->u_nargs; i++)
630 tcp->u_arg[i] = tcp->u_arg[i + 1];
631 }
632 break;
633#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634 }
635}
636#endif
637
638struct tcb *tcp_last = NULL;
639
640static int
641internal_syscall(tcp)
642struct tcb *tcp;
643{
644 /*
645 * We must always trace a few critical system calls in order to
646 * correctly support following forks in the presence of tracing
647 * qualifiers.
648 */
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000649 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000650#ifdef SYS_fork
651 case SYS_fork:
652#endif
653#ifdef SYS_vfork
654 case SYS_vfork:
655#endif
John Hughes4e36a812001-04-18 15:11:51 +0000656#ifdef SYS_fork1
657 case SYS_fork1:
658#endif
659#ifdef SYS_forkall
660 case SYS_forkall:
661#endif
662#ifdef SYS_rfork1
663 case SYS_rfork1:
664#endif
665#ifdef SYS_rforkall
666 case SYS_rforkall:
667#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000668#ifdef SYS_rfork
669 case SYS_rfork:
670#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671 internal_fork(tcp);
672 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000673#ifdef SYS_clone
674 case SYS_clone:
675 internal_clone(tcp);
676 break;
677#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000678#ifdef SYS_clone2
679 case SYS_clone2:
680 internal_clone(tcp);
681 break;
682#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000683#ifdef SYS_execv
684 case SYS_execv:
685#endif
686#ifdef SYS_execve
687 case SYS_execve:
688#endif
John Hughes4e36a812001-04-18 15:11:51 +0000689#ifdef SYS_rexecve
690 case SYS_rexecve:
691#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692 internal_exec(tcp);
693 break;
694
695#ifdef SYS_wait
696 case SYS_wait:
697#endif
698#ifdef SYS_wait4
699 case SYS_wait4:
700#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000701#ifdef SYS32_wait4
702 case SYS32_wait4:
703#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000704#ifdef SYS_waitpid
705 case SYS_waitpid:
706#endif
707#ifdef SYS_waitsys
708 case SYS_waitsys:
709#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000710 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000712#ifdef SYS_waitid
713 case SYS_waitid:
714 internal_wait(tcp, 3);
715 break;
716#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717
718#ifdef SYS_exit
719 case SYS_exit:
720#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000721#ifdef SYS32_exit
722 case SYS32_exit:
723#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000724#ifdef __NR_exit_group
725 case __NR_exit_group:
726#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000727#ifdef IA64
728 case 252: /* IA-32 __NR_exit_group */
729#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000730 internal_exit(tcp);
731 break;
732 }
733 return 0;
734}
735
Wichert Akkermanc7926982000-04-10 22:22:31 +0000736
737#ifdef LINUX
738#if defined (I386)
739 static long eax;
740#elif defined (IA64)
741 long r8, r10, psr;
742 long ia32 = 0;
743#elif defined (POWERPC)
744 static long result,flags;
745#elif defined (M68K)
746 static int d0;
747#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000748 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000749#elif defined (ALPHA)
750 static long r0;
751 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000752#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000753 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000754 static unsigned long trap;
755#elif defined(MIPS)
756 static long a3;
757 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000758#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000759 static long gpr2;
760 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000761 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000762#elif defined(HPPA)
763 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000764#elif defined(SH)
765 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000766#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000767 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000768#elif defined(X86_64)
769 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000770#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000771#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000772#ifdef FREEBSD
773 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000774#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000775
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000777get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778struct tcb *tcp;
779{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000783#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000786#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000787 if (tcp->flags & TCB_WAITEXECVE) {
788 /*
789 * When the execve system call completes successfully, the
790 * new process still has -ENOSYS (old style) or __NR_execve
791 * (new style) in gpr2. We cannot recover the scno again
792 * by disassembly, because the image that executed the
793 * syscall is gone now. Fortunately, we don't want it. We
794 * leave the flag set so that syscall_fixup can fake the
795 * result.
796 */
797 if (tcp->flags & TCB_INSYSCALL)
798 return 1;
799 /*
800 * This is the SIGTRAP after execve. We cannot try to read
801 * the system call here either.
802 */
803 tcp->flags &= ~TCB_WAITEXECVE;
804 return 0;
805 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000806
807 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
808 return -1;
809
810 if (syscall_mode != -ENOSYS) {
811 /*
812 * Since kernel version 2.5.44 the scno gets passed in gpr2.
813 */
814 scno = syscall_mode;
815 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000816 /*
817 * Old style of "passing" the scno via the SVC instruction.
818 */
819
820 long opcode, offset_reg, tmp;
821 void * svc_addr;
822 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
823 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
824 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
825 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000826
Michal Ludvig882eda82002-11-11 12:50:47 +0000827 if (upeek(pid, PT_PSWADDR, &pc) < 0)
828 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000829 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000830 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000831 if (errno) {
832 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000835
836 /*
837 * We have to check if the SVC got executed directly or via an
838 * EXECUTE instruction. In case of EXECUTE it is necessary to do
839 * instruction decoding to derive the system call number.
840 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
841 * so that this doesn't work if a SVC opcode is part of an EXECUTE
842 * opcode. Since there is no way to find out the opcode size this
843 * is the best we can do...
844 */
845
846 if ((opcode & 0xff00) == 0x0a00) {
847 /* SVC opcode */
848 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000849 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000850 else {
851 /* SVC got executed by EXECUTE instruction */
852
853 /*
854 * Do instruction decoding of EXECUTE. If you really want to
855 * understand this, read the Principles of Operations.
856 */
857 svc_addr = (void *) (opcode & 0xfff);
858
859 tmp = 0;
860 offset_reg = (opcode & 0x000f0000) >> 16;
861 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
862 return -1;
863 svc_addr += tmp;
864
865 tmp = 0;
866 offset_reg = (opcode & 0x0000f000) >> 12;
867 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
868 return -1;
869 svc_addr += tmp;
870
871 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
872 if (errno)
873 return -1;
874#if defined(S390X)
875 scno >>= 48;
876#else
877 scno >>= 16;
878#endif
879 tmp = 0;
880 offset_reg = (opcode & 0x00f00000) >> 20;
881 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
882 return -1;
883
884 scno = (scno | tmp) & 0xff;
885 }
886 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000887#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000888 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 return -1;
890 if (!(tcp->flags & TCB_INSYSCALL)) {
891 /* Check if we return from execve. */
892 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
893 tcp->flags &= ~TCB_WAITEXECVE;
894 return 0;
895 }
896 }
897#elif defined (I386)
898 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
899 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000900#elif defined (X86_64)
901 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
902 return -1;
903
Roland McGrath761b5d72002-12-15 23:58:31 +0000904 if (!(tcp->flags & TCB_INSYSCALL)) {
905 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000906 long val;
907
908 /* Check CS register value. On x86-64 linux it is:
909 * 0x33 for long mode (64 bit)
910 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000911 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000912 * to be cached.
913 */
914 if (upeek(pid, 8*CS, &val) < 0)
915 return -1;
916 switch(val)
917 {
918 case 0x23: currpers = 1; break;
919 case 0x33: currpers = 0; break;
920 default:
921 fprintf(stderr, "Unknown value CS=0x%02X while "
922 "detecting personality of process "
923 "PID=%d\n", (int)val, pid);
924 currpers = current_personality;
925 break;
926 }
927#if 0
928 /* This version analyzes the opcode of a syscall instruction.
929 * (int 0x80 on i386 vs. syscall on x86-64)
930 * It works, but is too complicated.
931 */
932 unsigned long val, rip, i;
933
934 if(upeek(pid, 8*RIP, &rip)<0)
935 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000936
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
938 rip-=2;
939 errno = 0;
940
Roland McGrath761b5d72002-12-15 23:58:31 +0000941 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
942 if (errno)
943 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 strerror(errno));
945 switch (call & 0xffff)
946 {
947 /* x86-64: syscall = 0x0f 0x05 */
948 case 0x050f: currpers = 0; break;
949 /* i386: int 0x80 = 0xcd 0x80 */
950 case 0x80cd: currpers = 1; break;
951 default:
952 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 "Unknown syscall opcode (0x%04X) while "
955 "detecting personality of process "
956 "PID=%d\n", (int)call, pid);
957 break;
958 }
959#endif
960 if(currpers != current_personality)
961 {
962 char *names[]={"64 bit", "32 bit"};
963 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000964 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000965 pid, names[current_personality]);
966 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000967 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000968#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000969# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000970 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000971 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000972 if (!(tcp->flags & TCB_INSYSCALL)) {
973 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000974 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975 return -1;
976 } else {
977 if (upeek (pid, PT_R15, &scno) < 0)
978 return -1;
979 }
Roland McGrathba954762003-03-05 06:29:06 +0000980 /* Check if we return from execve. */
981 if (tcp->flags & TCB_WAITEXECVE) {
982 tcp->flags &= ~TCB_WAITEXECVE;
983 return 0;
984 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000985 } else {
986 /* syscall in progress */
987 if (upeek (pid, PT_R8, &r8) < 0)
988 return -1;
989 if (upeek (pid, PT_R10, &r10) < 0)
990 return -1;
991 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000993 /*
994 * Read complete register set in one go.
995 */
996 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
997 return -1;
998
999 /*
1000 * We only need to grab the syscall number on syscall entry.
1001 */
1002 if (regs.ARM_ip == 0) {
1003 /*
1004 * Note: we only deal with only 32-bit CPUs here.
1005 */
1006 if (regs.ARM_cpsr & 0x20) {
1007 /*
1008 * Get the Thumb-mode system call number
1009 */
1010 scno = regs.ARM_r7;
1011 } else {
1012 /*
1013 * Get the ARM-mode system call number
1014 */
1015 errno = 0;
1016 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1017 if (errno)
1018 return -1;
1019
1020 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1021 tcp->flags &= ~TCB_WAITEXECVE;
1022 return 0;
1023 }
1024
1025 if ((scno & 0x0ff00000) != 0x0f900000) {
1026 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1027 scno);
1028 return -1;
1029 }
1030
1031 /*
1032 * Fixup the syscall number
1033 */
1034 scno &= 0x000fffff;
1035 }
1036
1037 if (tcp->flags & TCB_INSYSCALL) {
1038 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1039 tcp->flags &= ~TCB_INSYSCALL;
1040 }
1041 } else {
1042 if (!(tcp->flags & TCB_INSYSCALL)) {
1043 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1044 tcp->flags |= TCB_INSYSCALL;
1045 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 }
1047#elif defined (M68K)
1048 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1049 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001050#elif defined (MIPS)
1051 if (upeek(pid, REG_A3, &a3) < 0)
1052 return -1;
1053
1054 if(!(tcp->flags & TCB_INSYSCALL)) {
1055 if (upeek(pid, REG_V0, &scno) < 0)
1056 return -1;
1057
1058 if (scno < 0 || scno > nsyscalls) {
1059 if(a3 == 0 || a3 == -1) {
1060 if(debug)
1061 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1062 return 0;
1063 }
1064 }
1065 } else {
1066 if (upeek(pid, REG_V0, &r2) < 0)
1067 return -1;
1068 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069#elif defined (ALPHA)
1070 if (upeek(pid, REG_A3, &a3) < 0)
1071 return -1;
1072
1073 if (!(tcp->flags & TCB_INSYSCALL)) {
1074 if (upeek(pid, REG_R0, &scno) < 0)
1075 return -1;
1076
1077 /* Check if we return from execve. */
1078 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1079 tcp->flags &= ~TCB_WAITEXECVE;
1080 return 0;
1081 }
1082
1083 /*
1084 * Do some sanity checks to figure out if it's
1085 * really a syscall entry
1086 */
1087 if (scno < 0 || scno > nsyscalls) {
1088 if (a3 == 0 || a3 == -1) {
1089 if (debug)
1090 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1091 return 0;
1092 }
1093 }
1094 }
1095 else {
1096 if (upeek(pid, REG_R0, &r0) < 0)
1097 return -1;
1098 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001099#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 /* Everything we need is in the current register set. */
1101 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1102 return -1;
1103
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 /* If we are entering, then disassemble the syscall trap. */
1105 if (!(tcp->flags & TCB_INSYSCALL)) {
1106 /* Retrieve the syscall trap instruction. */
1107 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001108 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001109#if defined(SPARC64)
1110 trap >>= 32;
1111#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001112 if (errno)
1113 return -1;
1114
1115 /* Disassemble the trap to see what personality to use. */
1116 switch (trap) {
1117 case 0x91d02010:
1118 /* Linux/SPARC syscall trap. */
1119 set_personality(0);
1120 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001121 case 0x91d0206d:
1122 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001123 set_personality(2);
1124 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 case 0x91d02000:
1126 /* SunOS syscall trap. (pers 1) */
1127 fprintf(stderr,"syscall: SunOS no support\n");
1128 return -1;
1129 case 0x91d02008:
1130 /* Solaris 2.x syscall trap. (per 2) */
1131 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001132 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 case 0x91d02009:
1134 /* NetBSD/FreeBSD syscall trap. */
1135 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1136 return -1;
1137 case 0x91d02027:
1138 /* Solaris 2.x gettimeofday */
1139 set_personality(1);
1140 break;
1141 default:
1142 /* Unknown syscall trap. */
1143 if(tcp->flags & TCB_WAITEXECVE) {
1144 tcp->flags &= ~TCB_WAITEXECVE;
1145 return 0;
1146 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001147#if defined (SPARC64)
1148 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1149#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001150 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001151#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 return -1;
1153 }
1154
1155 /* Extract the system call number from the registers. */
1156 if (trap == 0x91d02027)
1157 scno = 156;
1158 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001159 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001161 scno = regs.r_o0;
1162 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 }
1164 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001165#elif defined(HPPA)
1166 if (upeek(pid, PT_GR20, &scno) < 0)
1167 return -1;
1168 if (!(tcp->flags & TCB_INSYSCALL)) {
1169 /* Check if we return from execve. */
1170 if ((tcp->flags & TCB_WAITEXECVE)) {
1171 tcp->flags &= ~TCB_WAITEXECVE;
1172 return 0;
1173 }
1174 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001175#elif defined(SH)
1176 /*
1177 * In the new syscall ABI, the system call number is in R3.
1178 */
1179 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1180 return -1;
1181
1182 if (scno < 0) {
1183 /* Odd as it may seem, a glibc bug has been known to cause
1184 glibc to issue bogus negative syscall numbers. So for
1185 our purposes, make strace print what it *should* have been */
1186 long correct_scno = (scno & 0xff);
1187 if (debug)
1188 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001189 "Detected glibc bug: bogus system call number = %ld, "
1190 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001191 scno,
1192 correct_scno);
1193 scno = correct_scno;
1194 }
1195
1196
1197 if (!(tcp->flags & TCB_INSYSCALL)) {
1198 /* Check if we return from execve. */
1199 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1200 tcp->flags &= ~TCB_WAITEXECVE;
1201 return 0;
1202 }
1203 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001204#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001205 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1206 return -1;
1207 scno &= 0xFFFF;
1208
1209 if (!(tcp->flags & TCB_INSYSCALL)) {
1210 /* Check if we return from execve. */
1211 if (tcp->flags & TCB_WAITEXECVE) {
1212 tcp->flags &= ~TCB_WAITEXECVE;
1213 return 0;
1214 }
1215 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001216#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217#endif /* LINUX */
1218#ifdef SUNOS4
1219 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1220 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001221#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001222 /* new syscall ABI returns result in R0 */
1223 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1224 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001225#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001226 /* ABI defines result returned in r9 */
1227 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1228 return -1;
1229
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001231#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001233 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001235#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001236 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001237#else /* FREEBSD */
1238 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1239 perror("pread");
1240 return -1;
1241 }
1242 switch (regs.r_eax) {
1243 case SYS_syscall:
1244 case SYS___syscall:
1245 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1246 break;
1247 default:
1248 scno = regs.r_eax;
1249 break;
1250 }
1251#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001252#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001253#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001254 if (!(tcp->flags & TCB_INSYSCALL))
1255 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001256 return 1;
1257}
1258
Pavel Machek4dc3b142000-02-01 17:58:41 +00001259
1260int
1261syscall_fixup(tcp)
1262struct tcb *tcp;
1263{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001264#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001265 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001266#else /* USE_PROCFS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001267 int scno = tcp->scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001268
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001270 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 if (
1272 scno == SYS_fork
1273#ifdef SYS_vfork
1274 || scno == SYS_vfork
1275#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001276#ifdef SYS_fork1
1277 || scno == SYS_fork1
1278#endif /* SYS_fork1 */
1279#ifdef SYS_forkall
1280 || scno == SYS_forkall
1281#endif /* SYS_forkall */
1282#ifdef SYS_rfork1
1283 || scno == SYS_rfork1
1284#endif /* SYS_fork1 */
1285#ifdef SYS_rforkall
1286 || scno == SYS_rforkall
1287#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001288 ) {
1289 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001290 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001292 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293 }
1294 else {
1295 fprintf(stderr, "syscall: missing entry\n");
1296 tcp->flags |= TCB_INSYSCALL;
1297 }
1298 }
1299 }
1300 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001301 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 fprintf(stderr, "syscall: missing exit\n");
1303 tcp->flags &= ~TCB_INSYSCALL;
1304 }
1305 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001306#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307#ifdef SUNOS4
1308 if (!(tcp->flags & TCB_INSYSCALL)) {
1309 if (scno == 0) {
1310 fprintf(stderr, "syscall: missing entry\n");
1311 tcp->flags |= TCB_INSYSCALL;
1312 }
1313 }
1314 else {
1315 if (scno != 0) {
1316 if (debug) {
1317 /*
1318 * This happens when a signal handler
1319 * for a signal which interrupted a
1320 * a system call makes another system call.
1321 */
1322 fprintf(stderr, "syscall: missing exit\n");
1323 }
1324 tcp->flags &= ~TCB_INSYSCALL;
1325 }
1326 }
1327#endif /* SUNOS4 */
1328#ifdef LINUX
1329#if defined (I386)
1330 if (upeek(pid, 4*EAX, &eax) < 0)
1331 return -1;
1332 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1333 if (debug)
1334 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1335 return 0;
1336 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001337#elif defined (X86_64)
1338 if (upeek(pid, 8*RAX, &rax) < 0)
1339 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001340 if (current_personality == 1)
1341 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001342 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1343 if (debug)
1344 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1345 return 0;
1346 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001347#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001348 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1349 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001350 if (syscall_mode != -ENOSYS)
1351 syscall_mode = tcp->scno;
1352 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001353 if (debug)
1354 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1355 return 0;
1356 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001357 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1358 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1359 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1360 /*
1361 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1362 * flag set for the post-execve SIGTRAP to see and reset.
1363 */
1364 gpr2 = 0;
1365 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366#elif defined (POWERPC)
1367# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001368 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001370 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 return -1;
1372 if (flags & SO_MASK)
1373 result = -result;
1374#elif defined (M68K)
1375 if (upeek(pid, 4*PT_D0, &d0) < 0)
1376 return -1;
1377 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1378 if (debug)
1379 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1380 return 0;
1381 }
1382#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001383 /*
1384 * Nothing required
1385 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001386#elif defined (HPPA)
1387 if (upeek(pid, PT_GR28, &r28) < 0)
1388 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001389#elif defined(IA64)
1390 if (upeek(pid, PT_R10, &r10) < 0)
1391 return -1;
1392 if (upeek(pid, PT_R8, &r8) < 0)
1393 return -1;
1394 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1395 if (debug)
1396 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1397 return 0;
1398 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399#endif
1400#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001401 return 1;
1402}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001403
Pavel Machek4dc3b142000-02-01 17:58:41 +00001404int
1405get_error(tcp)
1406struct tcb *tcp;
1407{
1408 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001410#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001411 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1412 tcp->u_rval = -1;
1413 u_error = -gpr2;
1414 }
1415 else {
1416 tcp->u_rval = gpr2;
1417 u_error = 0;
1418 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001419#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001420#ifdef I386
1421 if (eax < 0 && -eax < nerrnos) {
1422 tcp->u_rval = -1;
1423 u_error = -eax;
1424 }
1425 else {
1426 tcp->u_rval = eax;
1427 u_error = 0;
1428 }
1429#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001430#ifdef X86_64
1431 if (rax < 0 && -rax < nerrnos) {
1432 tcp->u_rval = -1;
1433 u_error = -rax;
1434 }
1435 else {
1436 tcp->u_rval = rax;
1437 u_error = 0;
1438 }
1439#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001440#ifdef IA64
1441 if (ia32) {
1442 int err;
1443
1444 err = (int)r8;
1445 if (err < 0 && -err < nerrnos) {
1446 tcp->u_rval = -1;
1447 u_error = -err;
1448 }
1449 else {
1450 tcp->u_rval = err;
1451 u_error = 0;
1452 }
1453 } else {
1454 if (r10) {
1455 tcp->u_rval = -1;
1456 u_error = r8;
1457 } else {
1458 tcp->u_rval = r8;
1459 u_error = 0;
1460 }
1461 }
1462#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001463#ifdef MIPS
1464 if (a3) {
1465 tcp->u_rval = -1;
1466 u_error = r2;
1467 } else {
1468 tcp->u_rval = r2;
1469 u_error = 0;
1470 }
1471#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001473 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474 tcp->u_rval = -1;
1475 u_error = -result;
1476 }
1477 else {
1478 tcp->u_rval = result;
1479 u_error = 0;
1480 }
1481#else /* !POWERPC */
1482#ifdef M68K
1483 if (d0 && (unsigned) -d0 < nerrnos) {
1484 tcp->u_rval = -1;
1485 u_error = -d0;
1486 }
1487 else {
1488 tcp->u_rval = d0;
1489 u_error = 0;
1490 }
1491#else /* !M68K */
1492#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001493 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001495 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 }
1497 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001498 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499 u_error = 0;
1500 }
1501#else /* !ARM */
1502#ifdef ALPHA
1503 if (a3) {
1504 tcp->u_rval = -1;
1505 u_error = r0;
1506 }
1507 else {
1508 tcp->u_rval = r0;
1509 u_error = 0;
1510 }
1511#else /* !ALPHA */
1512#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001513 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001515 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 }
1517 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001518 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519 u_error = 0;
1520 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001521#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001522#ifdef SPARC64
1523 if (regs.r_tstate & 0x1100000000UL) {
1524 tcp->u_rval = -1;
1525 u_error = regs.r_o0;
1526 }
1527 else {
1528 tcp->u_rval = regs.r_o0;
1529 u_error = 0;
1530 }
1531#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001532#ifdef HPPA
1533 if (r28 && (unsigned) -r28 < nerrnos) {
1534 tcp->u_rval = -1;
1535 u_error = -r28;
1536 }
1537 else {
1538 tcp->u_rval = r28;
1539 u_error = 0;
1540 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001541#else
1542#ifdef SH
1543 /* interpret R0 as return value or error number */
1544 if (r0 && (unsigned) -r0 < nerrnos) {
1545 tcp->u_rval = -1;
1546 u_error = -r0;
1547 }
1548 else {
1549 tcp->u_rval = r0;
1550 u_error = 0;
1551 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001552#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001553#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001554 /* interpret result as return value or error number */
1555 if (r9 && (unsigned) -r9 < nerrnos) {
1556 tcp->u_rval = -1;
1557 u_error = -r9;
1558 }
1559 else {
1560 tcp->u_rval = r9;
1561 u_error = 0;
1562 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001563#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001564#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001565#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001566#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001567#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568#endif /* ALPHA */
1569#endif /* ARM */
1570#endif /* M68K */
1571#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001572#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001573#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001574#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001576#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577#endif /* LINUX */
1578#ifdef SUNOS4
1579 /* get error code from user struct */
1580 if (upeek(pid, uoff(u_error), &u_error) < 0)
1581 return -1;
1582 u_error >>= 24; /* u_error is a char */
1583
1584 /* get system call return value */
1585 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1586 return -1;
1587#endif /* SUNOS4 */
1588#ifdef SVR4
1589#ifdef SPARC
1590 /* Judicious guessing goes a long way. */
1591 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1592 tcp->u_rval = -1;
1593 u_error = tcp->status.pr_reg[R_O0];
1594 }
1595 else {
1596 tcp->u_rval = tcp->status.pr_reg[R_O0];
1597 u_error = 0;
1598 }
1599#endif /* SPARC */
1600#ifdef I386
1601 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001602 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001604 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 }
1606 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001607 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001608#ifdef HAVE_LONG_LONG
1609 tcp->u_lrval =
1610 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1611 tcp->status.PR_REG[EAX];
1612#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 u_error = 0;
1614 }
1615#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001616#ifdef X86_64
1617 /* Wanna know how to kill an hour single-stepping? */
1618 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1619 tcp->u_rval = -1;
1620 u_error = tcp->status.PR_REG[RAX];
1621 }
1622 else {
1623 tcp->u_rval = tcp->status.PR_REG[RAX];
1624 u_error = 0;
1625 }
1626#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627#ifdef MIPS
1628 if (tcp->status.pr_reg[CTX_A3]) {
1629 tcp->u_rval = -1;
1630 u_error = tcp->status.pr_reg[CTX_V0];
1631 }
1632 else {
1633 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1634 u_error = 0;
1635 }
1636#endif /* MIPS */
1637#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001638#ifdef FREEBSD
1639 if (regs.r_eflags & PSL_C) {
1640 tcp->u_rval = -1;
1641 u_error = regs.r_eax;
1642 } else {
1643 tcp->u_rval = regs.r_eax;
1644 tcp->u_lrval =
1645 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1646 u_error = 0;
1647 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001648#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001649 tcp->u_error = u_error;
1650 return 1;
1651}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652
Roland McGrathb69f81b2002-12-21 23:25:18 +00001653int
1654force_result(tcp, error, rval)
1655 struct tcb *tcp;
1656 int error;
1657 long rval;
1658{
1659#ifdef LINUX
1660#if defined(S390) || defined(S390X)
1661 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001662 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1663 return -1;
1664#else /* !S390 && !S390X */
1665#ifdef I386
1666 eax = error ? -error : rval;
1667 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1668 return -1;
1669#else /* !I386 */
1670#ifdef X86_64
1671 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001672 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001673 return -1;
1674#else
1675#ifdef IA64
1676 if (ia32) {
1677 r8 = error ? -error : rval;
1678 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1679 return -1;
1680 }
1681 else {
1682 if (error) {
1683 r8 = error;
1684 r10 = -1;
1685 }
1686 else {
1687 r8 = rval;
1688 r10 = 0;
1689 }
1690 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1691 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1692 return -1;
1693 }
1694#else /* !IA64 */
1695#ifdef MIPS
1696 if (error) {
1697 r2 = error;
1698 a3 = -1;
1699 }
1700 else {
1701 r2 = rval;
1702 a3 = 0;
1703 }
1704 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1705 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1706 return -1;
1707#else
1708#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001709 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001710 return -1;
1711 if (error) {
1712 flags |= SO_MASK;
1713 result = error;
1714 }
1715 else {
1716 flags &= ~SO_MASK;
1717 result = rval;
1718 }
Roland McGratheb285352003-01-14 09:59:00 +00001719 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1720 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001721 return -1;
1722#else /* !POWERPC */
1723#ifdef M68K
1724 d0 = error ? -error : rval;
1725 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1726 return -1;
1727#else /* !M68K */
1728#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001729 regs.ARM_r0 = error ? -error : rval;
1730 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001731 return -1;
1732#else /* !ARM */
1733#ifdef ALPHA
1734 if (error) {
1735 a3 = -1;
1736 r0 = error;
1737 }
1738 else {
1739 a3 = 0;
1740 r0 = rval;
1741 }
1742 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1743 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1744 return -1;
1745#else /* !ALPHA */
1746#ifdef SPARC
1747 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1748 return -1;
1749 if (error) {
1750 regs.r_psr |= PSR_C;
1751 regs.r_o0 = error;
1752 }
1753 else {
1754 regs.r_psr &= ~PSR_C;
1755 regs.r_o0 = rval;
1756 }
1757 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1758 return -1;
1759#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001760#ifdef SPARC64
1761 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1762 return -1;
1763 if (error) {
1764 regs.r_tstate |= 0x1100000000UL;
1765 regs.r_o0 = error;
1766 }
1767 else {
1768 regs.r_tstate &= ~0x1100000000UL;
1769 regs.r_o0 = rval;
1770 }
1771 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1772 return -1;
1773#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001774#ifdef HPPA
1775 r28 = error ? -error : rval;
1776 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1777 return -1;
1778#else
1779#ifdef SH
1780 r0 = error ? -error : rval;
1781 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1782 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001783#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001784#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001785 r9 = error ? -error : rval;
1786 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1787 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001788#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001789#endif /* SH */
1790#endif /* HPPA */
1791#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001792#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793#endif /* ALPHA */
1794#endif /* ARM */
1795#endif /* M68K */
1796#endif /* POWERPC */
1797#endif /* MIPS */
1798#endif /* IA64 */
1799#endif /* X86_64 */
1800#endif /* I386 */
1801#endif /* S390 || S390X */
1802#endif /* LINUX */
1803#ifdef SUNOS4
1804 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1805 error << 24) < 0 ||
1806 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1807 return -1;
1808#endif /* SUNOS4 */
1809#ifdef SVR4
1810 /* XXX no clue */
1811 return -1;
1812#endif /* SVR4 */
1813#ifdef FREEBSD
1814 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1815 perror("pread");
1816 return -1;
1817 }
1818 if (error) {
1819 regs.r_eflags |= PSL_C;
1820 regs.r_eax = error;
1821 }
1822 else {
1823 regs.r_eflags &= ~PSL_C;
1824 regs.r_eax = rval;
1825 }
1826 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1827 perror("pwrite");
1828 return -1;
1829 }
1830#endif /* FREEBSD */
1831
1832 /* All branches reach here on success (only). */
1833 tcp->u_error = error;
1834 tcp->u_rval = rval;
1835 return 0;
1836}
1837
Pavel Machek4dc3b142000-02-01 17:58:41 +00001838int syscall_enter(tcp)
1839struct tcb *tcp;
1840{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001841#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001842 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001843#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001845#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001846 {
1847 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001848 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1849 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001850 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001851 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001852 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001853 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001854 return -1;
1855 }
1856 }
1857#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001858 {
1859 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001860 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1861 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001862 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001863 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001865 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1866 * for scno somewhere above here!
1867 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1869 return -1;
1870 }
1871 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001872#elif defined (IA64)
1873 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001874 if (!ia32) {
1875 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1876 /* be backwards compatible with kernel < 2.4.4... */
1877# ifndef PT_RBS_END
1878# define PT_RBS_END PT_AR_BSP
1879# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001880
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001881 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001882 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001883 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1884 return -1;
1885
1886 sof = (cfm >> 0) & 0x7f;
1887 sol = (cfm >> 7) & 0x7f;
1888 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1889
1890 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1891 && sysent[tcp->scno].nargs != -1)
1892 tcp->u_nargs = sysent[tcp->scno].nargs;
1893 else
1894 tcp->u_nargs = MAX_ARGS;
1895 for (i = 0; i < tcp->u_nargs; ++i) {
1896 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1897 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1898 return -1;
1899 }
1900 } else {
1901 int i;
1902
1903 if (/* EBX = out0 */
1904 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1905 /* ECX = out1 */
1906 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1907 /* EDX = out2 */
1908 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1909 /* ESI = out3 */
1910 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1911 /* EDI = out4 */
1912 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1913 /* EBP = out5 */
1914 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1915 return -1;
1916
1917 for (i = 0; i < 6; ++i)
1918 /* truncate away IVE sign-extension */
1919 tcp->u_arg[i] &= 0xffffffff;
1920
1921 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1922 && sysent[tcp->scno].nargs != -1)
1923 tcp->u_nargs = sysent[tcp->scno].nargs;
1924 else
1925 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001926 }
1927 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001928#elif defined (MIPS)
1929 {
1930 long sp;
1931 int i, nargs;
1932
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001933 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1934 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001935 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001936 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001937 if(nargs > 4) {
1938 if(upeek(pid, REG_SP, &sp) < 0)
1939 return -1;
1940 for(i = 0; i < 4; i++) {
1941 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1942 return -1;
1943 }
1944 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1945 (char *)(tcp->u_arg + 4));
1946 } else {
1947 for(i = 0; i < nargs; i++) {
1948 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1949 return -1;
1950 }
1951 }
1952 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001953#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00001954#ifndef PT_ORIG_R3
1955#define PT_ORIG_R3 34
1956#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001957 {
1958 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1960 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001961 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001962 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001963 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00001964 if (upeek(pid, (i==0) ?
1965 (sizeof(unsigned long)*PT_ORIG_R3) :
1966 ((i+PT_R3)*sizeof(unsigned long)),
1967 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968 return -1;
1969 }
1970 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001971#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001973 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001974
1975 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1976 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001977 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001978 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001979 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001980 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001981 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001982#elif defined (HPPA)
1983 {
1984 int i;
1985
1986 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1987 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001988 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001989 tcp->u_nargs = MAX_ARGS;
1990 for (i = 0; i < tcp->u_nargs; i++) {
1991 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1992 return -1;
1993 }
1994 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001995#elif defined(ARM)
1996 {
1997 int i;
1998
1999 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2000 tcp->u_nargs = sysent[tcp->scno].nargs;
2001 else
2002 tcp->u_nargs = MAX_ARGS;
2003 for (i = 0; i < tcp->u_nargs; i++)
2004 tcp->u_arg[i] = regs.uregs[i];
2005 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002006#elif defined(SH)
2007 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002008 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002009 static int syscall_regs[] = {
2010 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2011 REG_REG0, REG_REG0+1, REG_REG0+2
2012 };
2013
2014 tcp->u_nargs = sysent[tcp->scno].nargs;
2015 for (i = 0; i < tcp->u_nargs; i++) {
2016 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2017 return -1;
2018 }
2019 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002020#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002021 {
2022 int i;
2023 /* Registers used by SH5 Linux system calls for parameters */
2024 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2025
2026 /*
2027 * TODO: should also check that the number of arguments encoded
2028 * in the trap number matches the number strace expects.
2029 */
2030 /*
2031 assert(sysent[tcp->scno].nargs <
2032 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2033 */
2034
2035 tcp->u_nargs = sysent[tcp->scno].nargs;
2036 for (i = 0; i < tcp->u_nargs; i++) {
2037 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2038 return -1;
2039 }
2040 }
2041
Michal Ludvig0e035502002-09-23 15:41:01 +00002042#elif defined(X86_64)
2043 {
2044 int i;
2045 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2046 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002047 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002048 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002049
Michal Ludvig0e035502002-09-23 15:41:01 +00002050 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2051 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002052 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002053 tcp->u_nargs = MAX_ARGS;
2054 for (i = 0; i < tcp->u_nargs; i++) {
2055 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2056 return -1;
2057 }
2058 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002059#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002060 {
2061 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002062 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2063 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002064 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002065 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002066 for (i = 0; i < tcp->u_nargs; i++) {
2067 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2068 return -1;
2069 }
2070 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002071#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002072#endif /* LINUX */
2073#ifdef SUNOS4
2074 {
2075 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002076 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2077 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002078 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002079 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002080 for (i = 0; i < tcp->u_nargs; i++) {
2081 struct user *u;
2082
2083 if (upeek(pid, uoff(u_arg[0]) +
2084 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2085 return -1;
2086 }
2087 }
2088#endif /* SUNOS4 */
2089#ifdef SVR4
2090#ifdef MIPS
2091 /*
2092 * SGI is broken: even though it has pr_sysarg, it doesn't
2093 * set them on system call entry. Get a clue.
2094 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002095 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002096 tcp->u_nargs = sysent[tcp->scno].nargs;
2097 else
2098 tcp->u_nargs = tcp->status.pr_nsysarg;
2099 if (tcp->u_nargs > 4) {
2100 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2101 4*sizeof(tcp->u_arg[0]));
2102 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2103 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2104 }
2105 else {
2106 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2107 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2108 }
John Hughes25299712001-03-06 10:10:06 +00002109#elif UNIXWARE >= 2
2110 /*
2111 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2112 */
2113 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2114 tcp->u_nargs = sysent[tcp->scno].nargs;
2115 else
2116 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2117 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2118 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2119#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002120 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 tcp->u_nargs = sysent[tcp->scno].nargs;
2122 else
2123 tcp->u_nargs = tcp->status.pr_nsysarg;
2124 {
2125 int i;
2126 for (i = 0; i < tcp->u_nargs; i++)
2127 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2128 }
John Hughes25299712001-03-06 10:10:06 +00002129#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002130 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002131 tcp->u_nargs = sysent[tcp->scno].nargs;
2132 else
2133 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002134 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002135 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002136#else
2137 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002140#ifdef FREEBSD
2141 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2142 sysent[tcp->scno].nargs > tcp->status.val)
2143 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002144 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002145 tcp->u_nargs = tcp->status.val;
2146 if (tcp->u_nargs < 0)
2147 tcp->u_nargs = 0;
2148 if (tcp->u_nargs > MAX_ARGS)
2149 tcp->u_nargs = MAX_ARGS;
2150 switch(regs.r_eax) {
2151 case SYS___syscall:
2152 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2153 regs.r_esp + sizeof(int) + sizeof(quad_t));
2154 break;
2155 case SYS_syscall:
2156 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2157 regs.r_esp + 2 * sizeof(int));
2158 break;
2159 default:
2160 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2161 regs.r_esp + sizeof(int));
2162 break;
2163 }
2164#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002165 return 1;
2166}
2167
2168int
2169trace_syscall(tcp)
2170struct tcb *tcp;
2171{
2172 int sys_res;
2173 struct timeval tv;
2174 int res;
2175
2176 /* Measure the exit time as early as possible to avoid errors. */
2177 if (dtime && (tcp->flags & TCB_INSYSCALL))
2178 gettimeofday(&tv, NULL);
2179
2180 res = get_scno(tcp);
2181 if (res != 1)
2182 return res;
2183
2184 res = syscall_fixup(tcp);
2185 if (res != 1)
2186 return res;
2187
2188 if (tcp->flags & TCB_INSYSCALL) {
2189 long u_error;
2190 res = get_error(tcp);
2191 if (res != 1)
2192 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002193
2194 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002195 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2196 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002197 tcp->flags &= ~TCB_INSYSCALL;
2198 return 0;
2199 }
2200
2201 if (tcp->flags & TCB_REPRINT) {
2202 printleader(tcp);
2203 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002204 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002205 tprintf("syscall_%lu", tcp->scno);
2206 else
2207 tprintf("%s", sysent[tcp->scno].sys_name);
2208 tprintf(" resumed> ");
2209 }
2210
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002211 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002212 if (counts == NULL) {
2213 counts = calloc(sizeof *counts, nsyscalls);
2214 if (counts == NULL) {
2215 fprintf(stderr, "\
2216strace: out of memory for call counts\n");
2217 exit(1);
2218 }
2219 }
2220
2221 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002222 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002223 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002224 tv_sub(&tv, &tv, &tcp->etime);
2225#ifdef LINUX
2226 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002227 static struct timeval one_tick;
2228 if (one_tick.tv_usec == 0) {
2229 /* Initialize it. */
2230 struct itimerval it;
2231 memset(&it, 0, sizeof it);
2232 it.it_interval.tv_usec = 1;
2233 setitimer(ITIMER_REAL, &it, NULL);
2234 getitimer(ITIMER_REAL, &it);
2235 one_tick = it.it_interval;
2236 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002237
2238 if (tv_nz(&tcp->dtime))
2239 tv = tcp->dtime;
2240 else if (tv_cmp(&tv, &one_tick) > 0) {
2241 if (tv_cmp(&shortest, &one_tick) < 0)
2242 tv = shortest;
2243 else
2244 tv = one_tick;
2245 }
2246 }
2247#endif /* LINUX */
2248 if (tv_cmp(&tv, &shortest) < 0)
2249 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002250 tv_add(&counts[tcp->scno].time,
2251 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002252 tcp->flags &= ~TCB_INSYSCALL;
2253 return 0;
2254 }
2255
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002256 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002257 || (qual_flags[tcp->scno] & QUAL_RAW))
2258 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002259 else {
2260 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002261 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002262 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002263 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002264 u_error = tcp->u_error;
2265 tprintf(") ");
2266 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2268 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002269 if (u_error)
2270 tprintf("= -1 (errno %ld)", u_error);
2271 else
2272 tprintf("= %#lx", tcp->u_rval);
2273 }
2274 else if (!(sys_res & RVAL_NONE) && u_error) {
2275 switch (u_error) {
2276#ifdef LINUX
2277 case ERESTARTSYS:
2278 tprintf("= ? ERESTARTSYS (To be restarted)");
2279 break;
2280 case ERESTARTNOINTR:
2281 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2282 break;
2283 case ERESTARTNOHAND:
2284 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2285 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002286 case ERESTART_RESTARTBLOCK:
2287 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2288 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002289#endif /* LINUX */
2290 default:
2291 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002292 if (u_error < 0)
2293 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002294 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002295 tprintf("%s (%s)", errnoent[u_error],
2296 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002297 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002298 tprintf("ERRNO_%ld (%s)", u_error,
2299 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002300 break;
2301 }
2302 }
2303 else {
2304 if (sys_res & RVAL_NONE)
2305 tprintf("= ?");
2306 else {
2307 switch (sys_res & RVAL_MASK) {
2308 case RVAL_HEX:
2309 tprintf("= %#lx", tcp->u_rval);
2310 break;
2311 case RVAL_OCTAL:
2312 tprintf("= %#lo", tcp->u_rval);
2313 break;
2314 case RVAL_UDECIMAL:
2315 tprintf("= %lu", tcp->u_rval);
2316 break;
2317 case RVAL_DECIMAL:
2318 tprintf("= %ld", tcp->u_rval);
2319 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002320#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002321 case RVAL_LHEX:
2322 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002323 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002324 case RVAL_LOCTAL:
2325 tprintf("= %#llo", tcp->u_lrval);
2326 break;
2327 case RVAL_LUDECIMAL:
2328 tprintf("= %llu", tcp->u_lrval);
2329 break;
2330 case RVAL_LDECIMAL:
2331 tprintf("= %lld", tcp->u_lrval);
2332 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002333#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002334 default:
2335 fprintf(stderr,
2336 "invalid rval format\n");
2337 break;
2338 }
2339 }
2340 if ((sys_res & RVAL_STR) && tcp->auxstr)
2341 tprintf(" (%s)", tcp->auxstr);
2342 }
2343 if (dtime) {
2344 tv_sub(&tv, &tv, &tcp->etime);
2345 tprintf(" <%ld.%06ld>",
2346 (long) tv.tv_sec, (long) tv.tv_usec);
2347 }
2348 printtrailer(tcp);
2349
2350 dumpio(tcp);
2351 if (fflush(tcp->outf) == EOF)
2352 return -1;
2353 tcp->flags &= ~TCB_INSYSCALL;
2354 return 0;
2355 }
2356
2357 /* Entering system call */
2358 res = syscall_enter(tcp);
2359 if (res != 1)
2360 return res;
2361
Pavel Machekd8ae7e32000-02-01 17:17:25 +00002362 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002363#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002364#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA) && !defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002365 case SYS_socketcall:
2366 decode_subcall(tcp, SYS_socket_subcall,
2367 SYS_socket_nsubcalls, deref_style);
2368 break;
2369 case SYS_ipc:
2370 decode_subcall(tcp, SYS_ipc_subcall,
2371 SYS_ipc_nsubcalls, shift_style);
2372 break;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002373#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA && !X86_64 */
2374#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002375 case SYS_socketcall:
2376 sparc_socket_decode (tcp);
2377 break;
2378#endif
2379#endif /* LINUX */
2380#ifdef SVR4
2381#ifdef SYS_pgrpsys_subcall
2382 case SYS_pgrpsys:
2383 decode_subcall(tcp, SYS_pgrpsys_subcall,
2384 SYS_pgrpsys_nsubcalls, shift_style);
2385 break;
2386#endif /* SYS_pgrpsys_subcall */
2387#ifdef SYS_sigcall_subcall
2388 case SYS_sigcall:
2389 decode_subcall(tcp, SYS_sigcall_subcall,
2390 SYS_sigcall_nsubcalls, mask_style);
2391 break;
2392#endif /* SYS_sigcall_subcall */
2393 case SYS_msgsys:
2394 decode_subcall(tcp, SYS_msgsys_subcall,
2395 SYS_msgsys_nsubcalls, shift_style);
2396 break;
2397 case SYS_shmsys:
2398 decode_subcall(tcp, SYS_shmsys_subcall,
2399 SYS_shmsys_nsubcalls, shift_style);
2400 break;
2401 case SYS_semsys:
2402 decode_subcall(tcp, SYS_semsys_subcall,
2403 SYS_semsys_nsubcalls, shift_style);
2404 break;
2405#if 0 /* broken */
2406 case SYS_utssys:
2407 decode_subcall(tcp, SYS_utssys_subcall,
2408 SYS_utssys_nsubcalls, shift_style);
2409 break;
2410#endif
2411 case SYS_sysfs:
2412 decode_subcall(tcp, SYS_sysfs_subcall,
2413 SYS_sysfs_nsubcalls, shift_style);
2414 break;
2415 case SYS_spcall:
2416 decode_subcall(tcp, SYS_spcall_subcall,
2417 SYS_spcall_nsubcalls, shift_style);
2418 break;
2419#ifdef SYS_context_subcall
2420 case SYS_context:
2421 decode_subcall(tcp, SYS_context_subcall,
2422 SYS_context_nsubcalls, shift_style);
2423 break;
2424#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002425#ifdef SYS_door_subcall
2426 case SYS_door:
2427 decode_subcall(tcp, SYS_door_subcall,
2428 SYS_door_nsubcalls, door_style);
2429 break;
2430#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002431#ifdef SYS_kaio_subcall
2432 case SYS_kaio:
2433 decode_subcall(tcp, SYS_kaio_subcall,
2434 SYS_kaio_nsubcalls, shift_style);
2435 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002436#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002437#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002438#ifdef FREEBSD
2439 case SYS_msgsys:
2440 case SYS_shmsys:
2441 case SYS_semsys:
2442 decode_subcall(tcp, 0, 0, table_style);
2443 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002444#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002445#ifdef SUNOS4
2446 case SYS_semsys:
2447 decode_subcall(tcp, SYS_semsys_subcall,
2448 SYS_semsys_nsubcalls, shift_style);
2449 break;
2450 case SYS_msgsys:
2451 decode_subcall(tcp, SYS_msgsys_subcall,
2452 SYS_msgsys_nsubcalls, shift_style);
2453 break;
2454 case SYS_shmsys:
2455 decode_subcall(tcp, SYS_shmsys_subcall,
2456 SYS_shmsys_nsubcalls, shift_style);
2457 break;
2458#endif
2459 }
2460
2461 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002462 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463 tcp->flags |= TCB_INSYSCALL;
2464 return 0;
2465 }
2466
2467 if (cflag) {
2468 gettimeofday(&tcp->etime, NULL);
2469 tcp->flags |= TCB_INSYSCALL;
2470 return 0;
2471 }
2472
2473 printleader(tcp);
2474 tcp->flags &= ~TCB_REPRINT;
2475 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002476 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002477 tprintf("syscall_%lu(", tcp->scno);
2478 else
2479 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002480 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002481 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2482 sys_res = printargs(tcp);
2483 else
2484 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2485 if (fflush(tcp->outf) == EOF)
2486 return -1;
2487 tcp->flags |= TCB_INSYSCALL;
2488 /* Measure the entrance time as late as possible to avoid errors. */
2489 if (dtime)
2490 gettimeofday(&tcp->etime, NULL);
2491 return sys_res;
2492}
2493
2494int
2495printargs(tcp)
2496struct tcb *tcp;
2497{
2498 if (entering(tcp)) {
2499 int i;
2500
2501 for (i = 0; i < tcp->u_nargs; i++)
2502 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2503 }
2504 return 0;
2505}
2506
2507long
2508getrval2(tcp)
2509struct tcb *tcp;
2510{
2511 long val = -1;
2512
2513#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002514#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002515 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2517 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002518 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002519#elif defined(SH)
2520 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2521 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002522#elif defined(IA64)
2523 if (upeek(tcp->pid, PT_R9, &val) < 0)
2524 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002525#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002526#endif /* LINUX */
2527
2528#ifdef SUNOS4
2529 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2530 return -1;
2531#endif /* SUNOS4 */
2532
2533#ifdef SVR4
2534#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002535 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002536#endif /* SPARC */
2537#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002538 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002539#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002540#ifdef X86_64
2541 val = tcp->status.PR_REG[RDX];
2542#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002544 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545#endif /* MIPS */
2546#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002547#ifdef FREEBSD
2548 struct reg regs;
2549 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2550 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002551#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002552 return val;
2553}
2554
2555/*
2556 * Apparently, indirect system calls have already be converted by ptrace(2),
2557 * so if you see "indir" this program has gone astray.
2558 */
2559int
2560sys_indir(tcp)
2561struct tcb *tcp;
2562{
2563 int i, scno, nargs;
2564
2565 if (entering(tcp)) {
2566 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2567 fprintf(stderr, "Bogus syscall: %u\n", scno);
2568 return 0;
2569 }
2570 nargs = sysent[scno].nargs;
2571 tprintf("%s", sysent[scno].sys_name);
2572 for (i = 0; i < nargs; i++)
2573 tprintf(", %#lx", tcp->u_arg[i+1]);
2574 }
2575 return 0;
2576}
2577
2578static int
2579time_cmp(a, b)
2580void *a;
2581void *b;
2582{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002583 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002584}
2585
2586static int
2587syscall_cmp(a, b)
2588void *a;
2589void *b;
2590{
2591 return strcmp(sysent[*((int *) a)].sys_name,
2592 sysent[*((int *) b)].sys_name);
2593}
2594
2595static int
2596count_cmp(a, b)
2597void *a;
2598void *b;
2599{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002600 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601
2602 return (m < n) ? 1 : (m > n) ? -1 : 0;
2603}
2604
2605static int (*sortfun)();
2606static struct timeval overhead = { -1, -1 };
2607
2608void
2609set_sortby(sortby)
2610char *sortby;
2611{
2612 if (strcmp(sortby, "time") == 0)
2613 sortfun = time_cmp;
2614 else if (strcmp(sortby, "calls") == 0)
2615 sortfun = count_cmp;
2616 else if (strcmp(sortby, "name") == 0)
2617 sortfun = syscall_cmp;
2618 else if (strcmp(sortby, "nothing") == 0)
2619 sortfun = NULL;
2620 else {
2621 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2622 exit(1);
2623 }
2624}
2625
2626void set_overhead(n)
2627int n;
2628{
2629 overhead.tv_sec = n / 1000000;
2630 overhead.tv_usec = n % 1000000;
2631}
2632
2633void
2634call_summary(outf)
2635FILE *outf;
2636{
2637 int i, j;
2638 int call_cum, error_cum;
2639 struct timeval tv_cum, dtv;
2640 double percent;
2641 char *dashes = "-------------------------";
2642 char error_str[16];
2643
Roland McGrathe10e62a2004-09-04 04:20:43 +00002644 int *sorted_count = malloc(nsyscalls * sizeof(int));
2645
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002646 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2647 if (overhead.tv_sec == -1) {
2648 tv_mul(&overhead, &shortest, 8);
2649 tv_div(&overhead, &overhead, 10);
2650 }
2651 for (i = 0; i < nsyscalls; i++) {
2652 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002653 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002655 tv_mul(&dtv, &overhead, counts[i].calls);
2656 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2657 call_cum += counts[i].calls;
2658 error_cum += counts[i].errors;
2659 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002661 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002662 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2663 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2664 "% time", "seconds", "usecs/call",
2665 "calls", "errors", "syscall");
2666 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2667 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002668 if (counts) {
2669 for (i = 0; i < nsyscalls; i++) {
2670 j = sorted_count[i];
2671 if (counts[j].calls == 0)
2672 continue;
2673 tv_div(&dtv, &counts[j].time, counts[j].calls);
2674 if (counts[j].errors)
2675 sprintf(error_str, "%d", counts[j].errors);
2676 else
2677 error_str[0] = '\0';
2678 percent = (100.0 * tv_float(&counts[j].time)
2679 / tv_float(&tv_cum));
2680 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2681 percent, (long) counts[j].time.tv_sec,
2682 (long) counts[j].time.tv_usec,
2683 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2684 counts[j].calls,
2685 error_str, sysent[j].sys_name);
2686 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002688 free(sorted_count);
2689
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2691 dashes, dashes, dashes, dashes, dashes, dashes);
2692 if (error_cum)
2693 sprintf(error_str, "%d", error_cum);
2694 else
2695 error_str[0] = '\0';
2696 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2697 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2698 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002699
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700}