blob: 675b3f4f4a679ae8db3a1edd95aff9eb56cb814f [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;
Roland McGrath17352792005-06-07 23:21:26 +0000448 switch (known_scno(tcp)) {
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:
Roland McGrath17352792005-06-07 23:21:26 +0000458#elif defined SYS_sub_recv
459 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460#endif
461#ifdef SYS_recvfrom
462 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000463#elif defined SYS_sub_recvfrom
464 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000465#endif
466 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
467 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
468 break;
469 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000470#ifdef SYS_pwrite64
471 case SYS_pwrite64:
472#endif
473#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
474 case SYS_pwrite:
475#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000476#ifdef SYS_send
477 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000478#elif defined SYS_sub_send
479 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000480#endif
481#ifdef SYS_sendto
482 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000483#elif defined SYS_sub_sendto
484 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000485#endif
486 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
487 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
488 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000489#ifdef SYS_readv
490 case SYS_readv:
491 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
492 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
493 break;
494#endif
495#ifdef SYS_writev
496 case SYS_writev:
497
498 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
499 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
500 break;
501#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000502 }
503}
504
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000505#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000506enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000507#else /* FREEBSD */
508enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
509
510struct subcall {
511 int call;
512 int nsubcalls;
513 int subcalls[5];
514};
515
Roland McGratha4d48532005-06-08 20:45:28 +0000516static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000517 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000518#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000519 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000520#else
521 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
522#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000523 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
524};
525#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000526
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000527#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528
Roland McGratha4d48532005-06-08 20:45:28 +0000529static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530 /* SYS_SOCKET */ 97,
531 /* SYS_BIND */ 104,
532 /* SYS_CONNECT */ 98,
533 /* SYS_LISTEN */ 106,
534 /* SYS_ACCEPT */ 99,
535 /* SYS_GETSOCKNAME */ 150,
536 /* SYS_GETPEERNAME */ 141,
537 /* SYS_SOCKETPAIR */ 135,
538 /* SYS_SEND */ 101,
539 /* SYS_RECV */ 102,
540 /* SYS_SENDTO */ 133,
541 /* SYS_RECVFROM */ 125,
542 /* SYS_SHUTDOWN */ 134,
543 /* SYS_SETSOCKOPT */ 105,
544 /* SYS_GETSOCKOPT */ 118,
545 /* SYS_SENDMSG */ 114,
546 /* SYS_RECVMSG */ 113
547};
548
Roland McGratha4d48532005-06-08 20:45:28 +0000549#if defined (SPARC) || defined (SPARC64)
550static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000551sparc_socket_decode (tcp)
552struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553{
554 volatile long addr;
555 volatile int i, n;
556
557 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
558 return;
559 }
560 tcp->scno = socket_map [tcp->u_arg [0]-1];
561 n = tcp->u_nargs = sysent [tcp->scno].nargs;
562 addr = tcp->u_arg [1];
563 for (i = 0; i < n; i++){
564 int arg;
565 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
566 arg = 0;
567 tcp->u_arg [i] = arg;
568 addr += sizeof (arg);
569 }
570}
Roland McGratha4d48532005-06-08 20:45:28 +0000571#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572
Roland McGratha4d48532005-06-08 20:45:28 +0000573static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574decode_subcall(tcp, subcall, nsubcalls, style)
575struct tcb *tcp;
576int subcall;
577int nsubcalls;
578enum subcall_style style;
579{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000580 long addr, mask, arg;
581 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000582
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 switch (style) {
584 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000585 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
586 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587 tcp->scno = subcall + tcp->u_arg[0];
588 if (sysent[tcp->scno].nargs != -1)
589 tcp->u_nargs = sysent[tcp->scno].nargs;
590 else
591 tcp->u_nargs--;
592 for (i = 0; i < tcp->u_nargs; i++)
593 tcp->u_arg[i] = tcp->u_arg[i + 1];
594 break;
595 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000596 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
597 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 tcp->scno = subcall + tcp->u_arg[0];
599 addr = tcp->u_arg[1];
600 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
601 if (umove(tcp, addr, &arg) < 0)
602 arg = 0;
603 tcp->u_arg[i] = arg;
604 addr += sizeof(arg);
605 }
606 tcp->u_nargs = sysent[tcp->scno].nargs;
607 break;
608 case mask_style:
609 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000610 for (i = 0; mask; i++)
611 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000612 if (i >= nsubcalls)
613 return;
614 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 tcp->scno = subcall + i;
616 if (sysent[tcp->scno].nargs != -1)
617 tcp->u_nargs = sysent[tcp->scno].nargs;
618 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000619 case door_style:
620 /*
621 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000623 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
625 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000626 tcp->scno = subcall + tcp->u_arg[5];
627 if (sysent[tcp->scno].nargs != -1)
628 tcp->u_nargs = sysent[tcp->scno].nargs;
629 else
630 tcp->u_nargs--;
631 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000632#ifdef FREEBSD
633 case table_style:
634 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
635 if (subcalls_table[i].call == tcp->scno) break;
636 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
637 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
638 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
639 for (i = 0; i < tcp->u_nargs; i++)
640 tcp->u_arg[i] = tcp->u_arg[i + 1];
641 }
642 break;
643#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000644 }
645}
646#endif
647
648struct tcb *tcp_last = NULL;
649
650static int
651internal_syscall(tcp)
652struct tcb *tcp;
653{
654 /*
655 * We must always trace a few critical system calls in order to
656 * correctly support following forks in the presence of tracing
657 * qualifiers.
658 */
Roland McGrath17352792005-06-07 23:21:26 +0000659 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000660#ifdef SYS_fork
661 case SYS_fork:
662#endif
663#ifdef SYS_vfork
664 case SYS_vfork:
665#endif
John Hughes4e36a812001-04-18 15:11:51 +0000666#ifdef SYS_fork1
667 case SYS_fork1:
668#endif
669#ifdef SYS_forkall
670 case SYS_forkall:
671#endif
672#ifdef SYS_rfork1
673 case SYS_rfork1:
674#endif
675#ifdef SYS_rforkall
676 case SYS_rforkall:
677#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000678#ifdef SYS_rfork
679 case SYS_rfork:
680#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681 internal_fork(tcp);
682 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000683#ifdef SYS_clone
684 case SYS_clone:
685 internal_clone(tcp);
686 break;
687#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000688#ifdef SYS_clone2
689 case SYS_clone2:
690 internal_clone(tcp);
691 break;
692#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000693#ifdef SYS_execv
694 case SYS_execv:
695#endif
696#ifdef SYS_execve
697 case SYS_execve:
698#endif
John Hughes4e36a812001-04-18 15:11:51 +0000699#ifdef SYS_rexecve
700 case SYS_rexecve:
701#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000702 internal_exec(tcp);
703 break;
704
705#ifdef SYS_wait
706 case SYS_wait:
707#endif
708#ifdef SYS_wait4
709 case SYS_wait4:
710#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000711#ifdef SYS32_wait4
712 case SYS32_wait4:
713#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714#ifdef SYS_waitpid
715 case SYS_waitpid:
716#endif
717#ifdef SYS_waitsys
718 case SYS_waitsys:
719#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000720 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000721 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000722#ifdef SYS_waitid
723 case SYS_waitid:
724 internal_wait(tcp, 3);
725 break;
726#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727
728#ifdef SYS_exit
729 case SYS_exit:
730#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000731#ifdef SYS32_exit
732 case SYS32_exit:
733#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000734#ifdef __NR_exit_group
735 case __NR_exit_group:
736#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000737#ifdef IA64
738 case 252: /* IA-32 __NR_exit_group */
739#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740 internal_exit(tcp);
741 break;
742 }
743 return 0;
744}
745
Wichert Akkermanc7926982000-04-10 22:22:31 +0000746
747#ifdef LINUX
748#if defined (I386)
749 static long eax;
750#elif defined (IA64)
751 long r8, r10, psr;
752 long ia32 = 0;
753#elif defined (POWERPC)
754 static long result,flags;
755#elif defined (M68K)
756 static int d0;
757#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000758 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000759#elif defined (ALPHA)
760 static long r0;
761 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000762#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000763 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764 static unsigned long trap;
765#elif defined(MIPS)
766 static long a3;
767 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000768#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000769 static long gpr2;
770 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000771 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000772#elif defined(HPPA)
773 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000774#elif defined(SH)
775 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000776#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000777 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000778#elif defined(X86_64)
779 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000782#ifdef FREEBSD
783 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000784#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000785
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000787get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788struct tcb *tcp;
789{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000791#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000793#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000795#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000796#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000797 if (tcp->flags & TCB_WAITEXECVE) {
798 /*
799 * When the execve system call completes successfully, the
800 * new process still has -ENOSYS (old style) or __NR_execve
801 * (new style) in gpr2. We cannot recover the scno again
802 * by disassembly, because the image that executed the
803 * syscall is gone now. Fortunately, we don't want it. We
804 * leave the flag set so that syscall_fixup can fake the
805 * result.
806 */
807 if (tcp->flags & TCB_INSYSCALL)
808 return 1;
809 /*
810 * This is the SIGTRAP after execve. We cannot try to read
811 * the system call here either.
812 */
813 tcp->flags &= ~TCB_WAITEXECVE;
814 return 0;
815 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000816
817 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
818 return -1;
819
820 if (syscall_mode != -ENOSYS) {
821 /*
822 * Since kernel version 2.5.44 the scno gets passed in gpr2.
823 */
824 scno = syscall_mode;
825 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000826 /*
827 * Old style of "passing" the scno via the SVC instruction.
828 */
829
830 long opcode, offset_reg, tmp;
831 void * svc_addr;
832 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
833 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
834 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
835 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000836
Michal Ludvig882eda82002-11-11 12:50:47 +0000837 if (upeek(pid, PT_PSWADDR, &pc) < 0)
838 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000839 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000841 if (errno) {
842 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000844 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000845
846 /*
847 * We have to check if the SVC got executed directly or via an
848 * EXECUTE instruction. In case of EXECUTE it is necessary to do
849 * instruction decoding to derive the system call number.
850 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
851 * so that this doesn't work if a SVC opcode is part of an EXECUTE
852 * opcode. Since there is no way to find out the opcode size this
853 * is the best we can do...
854 */
855
856 if ((opcode & 0xff00) == 0x0a00) {
857 /* SVC opcode */
858 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000859 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000860 else {
861 /* SVC got executed by EXECUTE instruction */
862
863 /*
864 * Do instruction decoding of EXECUTE. If you really want to
865 * understand this, read the Principles of Operations.
866 */
867 svc_addr = (void *) (opcode & 0xfff);
868
869 tmp = 0;
870 offset_reg = (opcode & 0x000f0000) >> 16;
871 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
872 return -1;
873 svc_addr += tmp;
874
875 tmp = 0;
876 offset_reg = (opcode & 0x0000f000) >> 12;
877 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
878 return -1;
879 svc_addr += tmp;
880
881 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
882 if (errno)
883 return -1;
884#if defined(S390X)
885 scno >>= 48;
886#else
887 scno >>= 16;
888#endif
889 tmp = 0;
890 offset_reg = (opcode & 0x00f00000) >> 20;
891 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
892 return -1;
893
894 scno = (scno | tmp) & 0xff;
895 }
896 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000897#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000898 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 return -1;
900 if (!(tcp->flags & TCB_INSYSCALL)) {
901 /* Check if we return from execve. */
902 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
903 tcp->flags &= ~TCB_WAITEXECVE;
904 return 0;
905 }
906 }
907#elif defined (I386)
908 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
909 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000910#elif defined (X86_64)
911 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
912 return -1;
913
Roland McGrath761b5d72002-12-15 23:58:31 +0000914 if (!(tcp->flags & TCB_INSYSCALL)) {
915 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000916 long val;
917
918 /* Check CS register value. On x86-64 linux it is:
919 * 0x33 for long mode (64 bit)
920 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000921 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 * to be cached.
923 */
924 if (upeek(pid, 8*CS, &val) < 0)
925 return -1;
926 switch(val)
927 {
928 case 0x23: currpers = 1; break;
929 case 0x33: currpers = 0; break;
930 default:
931 fprintf(stderr, "Unknown value CS=0x%02X while "
932 "detecting personality of process "
933 "PID=%d\n", (int)val, pid);
934 currpers = current_personality;
935 break;
936 }
937#if 0
938 /* This version analyzes the opcode of a syscall instruction.
939 * (int 0x80 on i386 vs. syscall on x86-64)
940 * It works, but is too complicated.
941 */
942 unsigned long val, rip, i;
943
944 if(upeek(pid, 8*RIP, &rip)<0)
945 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000946
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
948 rip-=2;
949 errno = 0;
950
Roland McGrath761b5d72002-12-15 23:58:31 +0000951 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
952 if (errno)
953 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 strerror(errno));
955 switch (call & 0xffff)
956 {
957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000963 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
966 "PID=%d\n", (int)call, pid);
967 break;
968 }
969#endif
970 if(currpers != current_personality)
971 {
972 char *names[]={"64 bit", "32 bit"};
973 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000974 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000975 pid, names[current_personality]);
976 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000977 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000978#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000979# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000981 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000982 if (!(tcp->flags & TCB_INSYSCALL)) {
983 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000984 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000985 return -1;
986 } else {
987 if (upeek (pid, PT_R15, &scno) < 0)
988 return -1;
989 }
Roland McGrathba954762003-03-05 06:29:06 +0000990 /* Check if we return from execve. */
991 if (tcp->flags & TCB_WAITEXECVE) {
992 tcp->flags &= ~TCB_WAITEXECVE;
993 return 0;
994 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000995 } else {
996 /* syscall in progress */
997 if (upeek (pid, PT_R8, &r8) < 0)
998 return -1;
999 if (upeek (pid, PT_R10, &r10) < 0)
1000 return -1;
1001 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001003 /*
1004 * Read complete register set in one go.
1005 */
1006 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1007 return -1;
1008
1009 /*
1010 * We only need to grab the syscall number on syscall entry.
1011 */
1012 if (regs.ARM_ip == 0) {
1013 /*
1014 * Note: we only deal with only 32-bit CPUs here.
1015 */
1016 if (regs.ARM_cpsr & 0x20) {
1017 /*
1018 * Get the Thumb-mode system call number
1019 */
1020 scno = regs.ARM_r7;
1021 } else {
1022 /*
1023 * Get the ARM-mode system call number
1024 */
1025 errno = 0;
1026 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1027 if (errno)
1028 return -1;
1029
1030 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1031 tcp->flags &= ~TCB_WAITEXECVE;
1032 return 0;
1033 }
1034
1035 if ((scno & 0x0ff00000) != 0x0f900000) {
1036 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1037 scno);
1038 return -1;
1039 }
1040
1041 /*
1042 * Fixup the syscall number
1043 */
1044 scno &= 0x000fffff;
1045 }
1046
1047 if (tcp->flags & TCB_INSYSCALL) {
1048 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1049 tcp->flags &= ~TCB_INSYSCALL;
1050 }
1051 } else {
1052 if (!(tcp->flags & TCB_INSYSCALL)) {
1053 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1054 tcp->flags |= TCB_INSYSCALL;
1055 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056 }
1057#elif defined (M68K)
1058 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1059 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001060#elif defined (MIPS)
1061 if (upeek(pid, REG_A3, &a3) < 0)
1062 return -1;
1063
1064 if(!(tcp->flags & TCB_INSYSCALL)) {
1065 if (upeek(pid, REG_V0, &scno) < 0)
1066 return -1;
1067
1068 if (scno < 0 || scno > nsyscalls) {
1069 if(a3 == 0 || a3 == -1) {
1070 if(debug)
1071 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1072 return 0;
1073 }
1074 }
1075 } else {
1076 if (upeek(pid, REG_V0, &r2) < 0)
1077 return -1;
1078 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079#elif defined (ALPHA)
1080 if (upeek(pid, REG_A3, &a3) < 0)
1081 return -1;
1082
1083 if (!(tcp->flags & TCB_INSYSCALL)) {
1084 if (upeek(pid, REG_R0, &scno) < 0)
1085 return -1;
1086
1087 /* Check if we return from execve. */
1088 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1089 tcp->flags &= ~TCB_WAITEXECVE;
1090 return 0;
1091 }
1092
1093 /*
1094 * Do some sanity checks to figure out if it's
1095 * really a syscall entry
1096 */
1097 if (scno < 0 || scno > nsyscalls) {
1098 if (a3 == 0 || a3 == -1) {
1099 if (debug)
1100 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1101 return 0;
1102 }
1103 }
1104 }
1105 else {
1106 if (upeek(pid, REG_R0, &r0) < 0)
1107 return -1;
1108 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001109#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001110 /* Everything we need is in the current register set. */
1111 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1112 return -1;
1113
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 /* If we are entering, then disassemble the syscall trap. */
1115 if (!(tcp->flags & TCB_INSYSCALL)) {
1116 /* Retrieve the syscall trap instruction. */
1117 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001118 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001119#if defined(SPARC64)
1120 trap >>= 32;
1121#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 if (errno)
1123 return -1;
1124
1125 /* Disassemble the trap to see what personality to use. */
1126 switch (trap) {
1127 case 0x91d02010:
1128 /* Linux/SPARC syscall trap. */
1129 set_personality(0);
1130 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001131 case 0x91d0206d:
1132 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001133 set_personality(2);
1134 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 case 0x91d02000:
1136 /* SunOS syscall trap. (pers 1) */
1137 fprintf(stderr,"syscall: SunOS no support\n");
1138 return -1;
1139 case 0x91d02008:
1140 /* Solaris 2.x syscall trap. (per 2) */
1141 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001142 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 case 0x91d02009:
1144 /* NetBSD/FreeBSD syscall trap. */
1145 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1146 return -1;
1147 case 0x91d02027:
1148 /* Solaris 2.x gettimeofday */
1149 set_personality(1);
1150 break;
1151 default:
1152 /* Unknown syscall trap. */
1153 if(tcp->flags & TCB_WAITEXECVE) {
1154 tcp->flags &= ~TCB_WAITEXECVE;
1155 return 0;
1156 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001157#if defined (SPARC64)
1158 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1159#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001160 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001161#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 return -1;
1163 }
1164
1165 /* Extract the system call number from the registers. */
1166 if (trap == 0x91d02027)
1167 scno = 156;
1168 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001169 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001171 scno = regs.r_o0;
1172 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 }
1174 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001175#elif defined(HPPA)
1176 if (upeek(pid, PT_GR20, &scno) < 0)
1177 return -1;
1178 if (!(tcp->flags & TCB_INSYSCALL)) {
1179 /* Check if we return from execve. */
1180 if ((tcp->flags & TCB_WAITEXECVE)) {
1181 tcp->flags &= ~TCB_WAITEXECVE;
1182 return 0;
1183 }
1184 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001185#elif defined(SH)
1186 /*
1187 * In the new syscall ABI, the system call number is in R3.
1188 */
1189 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1190 return -1;
1191
1192 if (scno < 0) {
1193 /* Odd as it may seem, a glibc bug has been known to cause
1194 glibc to issue bogus negative syscall numbers. So for
1195 our purposes, make strace print what it *should* have been */
1196 long correct_scno = (scno & 0xff);
1197 if (debug)
1198 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001199 "Detected glibc bug: bogus system call number = %ld, "
1200 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001201 scno,
1202 correct_scno);
1203 scno = correct_scno;
1204 }
1205
1206
1207 if (!(tcp->flags & TCB_INSYSCALL)) {
1208 /* Check if we return from execve. */
1209 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1210 tcp->flags &= ~TCB_WAITEXECVE;
1211 return 0;
1212 }
1213 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001214#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001215 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1216 return -1;
1217 scno &= 0xFFFF;
1218
1219 if (!(tcp->flags & TCB_INSYSCALL)) {
1220 /* Check if we return from execve. */
1221 if (tcp->flags & TCB_WAITEXECVE) {
1222 tcp->flags &= ~TCB_WAITEXECVE;
1223 return 0;
1224 }
1225 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001226#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227#endif /* LINUX */
1228#ifdef SUNOS4
1229 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1230 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001231#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001232 /* new syscall ABI returns result in R0 */
1233 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1234 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001235#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001236 /* ABI defines result returned in r9 */
1237 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1238 return -1;
1239
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001241#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001243 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001246 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001247#else /* FREEBSD */
1248 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1249 perror("pread");
1250 return -1;
1251 }
1252 switch (regs.r_eax) {
1253 case SYS_syscall:
1254 case SYS___syscall:
1255 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1256 break;
1257 default:
1258 scno = regs.r_eax;
1259 break;
1260 }
1261#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001263#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001264 if (!(tcp->flags & TCB_INSYSCALL))
1265 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001266 return 1;
1267}
1268
Pavel Machek4dc3b142000-02-01 17:58:41 +00001269
Roland McGrath17352792005-06-07 23:21:26 +00001270long
1271known_scno(tcp)
1272struct tcb *tcp;
1273{
1274 long scno = tcp->scno;
1275 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1276 scno = sysent[scno].native_scno;
1277 else
1278 scno += NR_SYSCALL_BASE;
1279 return scno;
1280}
1281
Roland McGratha4d48532005-06-08 20:45:28 +00001282static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001283syscall_fixup(tcp)
1284struct tcb *tcp;
1285{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001286#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001287 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001288#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001289 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001290
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001292 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293 if (
1294 scno == SYS_fork
1295#ifdef SYS_vfork
1296 || scno == SYS_vfork
1297#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001298#ifdef SYS_fork1
1299 || scno == SYS_fork1
1300#endif /* SYS_fork1 */
1301#ifdef SYS_forkall
1302 || scno == SYS_forkall
1303#endif /* SYS_forkall */
1304#ifdef SYS_rfork1
1305 || scno == SYS_rfork1
1306#endif /* SYS_fork1 */
1307#ifdef SYS_rforkall
1308 || scno == SYS_rforkall
1309#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310 ) {
1311 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001312 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001314 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315 }
1316 else {
1317 fprintf(stderr, "syscall: missing entry\n");
1318 tcp->flags |= TCB_INSYSCALL;
1319 }
1320 }
1321 }
1322 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001323 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324 fprintf(stderr, "syscall: missing exit\n");
1325 tcp->flags &= ~TCB_INSYSCALL;
1326 }
1327 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001328#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329#ifdef SUNOS4
1330 if (!(tcp->flags & TCB_INSYSCALL)) {
1331 if (scno == 0) {
1332 fprintf(stderr, "syscall: missing entry\n");
1333 tcp->flags |= TCB_INSYSCALL;
1334 }
1335 }
1336 else {
1337 if (scno != 0) {
1338 if (debug) {
1339 /*
1340 * This happens when a signal handler
1341 * for a signal which interrupted a
1342 * a system call makes another system call.
1343 */
1344 fprintf(stderr, "syscall: missing exit\n");
1345 }
1346 tcp->flags &= ~TCB_INSYSCALL;
1347 }
1348 }
1349#endif /* SUNOS4 */
1350#ifdef LINUX
1351#if defined (I386)
1352 if (upeek(pid, 4*EAX, &eax) < 0)
1353 return -1;
1354 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1355 if (debug)
1356 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1357 return 0;
1358 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001359#elif defined (X86_64)
1360 if (upeek(pid, 8*RAX, &rax) < 0)
1361 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001362 if (current_personality == 1)
1363 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001364 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1365 if (debug)
1366 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1367 return 0;
1368 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001369#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001370 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1371 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001372 if (syscall_mode != -ENOSYS)
1373 syscall_mode = tcp->scno;
1374 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001375 if (debug)
1376 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1377 return 0;
1378 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001379 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1380 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1381 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1382 /*
1383 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1384 * flag set for the post-execve SIGTRAP to see and reset.
1385 */
1386 gpr2 = 0;
1387 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388#elif defined (POWERPC)
1389# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001390 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001392 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001393 return -1;
1394 if (flags & SO_MASK)
1395 result = -result;
1396#elif defined (M68K)
1397 if (upeek(pid, 4*PT_D0, &d0) < 0)
1398 return -1;
1399 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1400 if (debug)
1401 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1402 return 0;
1403 }
1404#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001405 /*
1406 * Nothing required
1407 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001408#elif defined (HPPA)
1409 if (upeek(pid, PT_GR28, &r28) < 0)
1410 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001411#elif defined(IA64)
1412 if (upeek(pid, PT_R10, &r10) < 0)
1413 return -1;
1414 if (upeek(pid, PT_R8, &r8) < 0)
1415 return -1;
1416 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1417 if (debug)
1418 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1419 return 0;
1420 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001421#endif
1422#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001423 return 1;
1424}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001425
Roland McGratha4d48532005-06-08 20:45:28 +00001426static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001427get_error(tcp)
1428struct tcb *tcp;
1429{
1430 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001431#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001432#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001433 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1434 tcp->u_rval = -1;
1435 u_error = -gpr2;
1436 }
1437 else {
1438 tcp->u_rval = gpr2;
1439 u_error = 0;
1440 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001441#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001442#ifdef I386
1443 if (eax < 0 && -eax < nerrnos) {
1444 tcp->u_rval = -1;
1445 u_error = -eax;
1446 }
1447 else {
1448 tcp->u_rval = eax;
1449 u_error = 0;
1450 }
1451#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001452#ifdef X86_64
1453 if (rax < 0 && -rax < nerrnos) {
1454 tcp->u_rval = -1;
1455 u_error = -rax;
1456 }
1457 else {
1458 tcp->u_rval = rax;
1459 u_error = 0;
1460 }
1461#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001462#ifdef IA64
1463 if (ia32) {
1464 int err;
1465
1466 err = (int)r8;
1467 if (err < 0 && -err < nerrnos) {
1468 tcp->u_rval = -1;
1469 u_error = -err;
1470 }
1471 else {
1472 tcp->u_rval = err;
1473 u_error = 0;
1474 }
1475 } else {
1476 if (r10) {
1477 tcp->u_rval = -1;
1478 u_error = r8;
1479 } else {
1480 tcp->u_rval = r8;
1481 u_error = 0;
1482 }
1483 }
1484#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001485#ifdef MIPS
1486 if (a3) {
1487 tcp->u_rval = -1;
1488 u_error = r2;
1489 } else {
1490 tcp->u_rval = r2;
1491 u_error = 0;
1492 }
1493#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001495 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 tcp->u_rval = -1;
1497 u_error = -result;
1498 }
1499 else {
1500 tcp->u_rval = result;
1501 u_error = 0;
1502 }
1503#else /* !POWERPC */
1504#ifdef M68K
1505 if (d0 && (unsigned) -d0 < nerrnos) {
1506 tcp->u_rval = -1;
1507 u_error = -d0;
1508 }
1509 else {
1510 tcp->u_rval = d0;
1511 u_error = 0;
1512 }
1513#else /* !M68K */
1514#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001515 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001517 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001518 }
1519 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001520 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521 u_error = 0;
1522 }
1523#else /* !ARM */
1524#ifdef ALPHA
1525 if (a3) {
1526 tcp->u_rval = -1;
1527 u_error = r0;
1528 }
1529 else {
1530 tcp->u_rval = r0;
1531 u_error = 0;
1532 }
1533#else /* !ALPHA */
1534#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001535 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001536 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001537 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001538 }
1539 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001540 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541 u_error = 0;
1542 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001543#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001544#ifdef SPARC64
1545 if (regs.r_tstate & 0x1100000000UL) {
1546 tcp->u_rval = -1;
1547 u_error = regs.r_o0;
1548 }
1549 else {
1550 tcp->u_rval = regs.r_o0;
1551 u_error = 0;
1552 }
1553#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001554#ifdef HPPA
1555 if (r28 && (unsigned) -r28 < nerrnos) {
1556 tcp->u_rval = -1;
1557 u_error = -r28;
1558 }
1559 else {
1560 tcp->u_rval = r28;
1561 u_error = 0;
1562 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001563#else
1564#ifdef SH
1565 /* interpret R0 as return value or error number */
1566 if (r0 && (unsigned) -r0 < nerrnos) {
1567 tcp->u_rval = -1;
1568 u_error = -r0;
1569 }
1570 else {
1571 tcp->u_rval = r0;
1572 u_error = 0;
1573 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001574#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001575#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001576 /* interpret result as return value or error number */
1577 if (r9 && (unsigned) -r9 < nerrnos) {
1578 tcp->u_rval = -1;
1579 u_error = -r9;
1580 }
1581 else {
1582 tcp->u_rval = r9;
1583 u_error = 0;
1584 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001585#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001586#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001587#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001589#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590#endif /* ALPHA */
1591#endif /* ARM */
1592#endif /* M68K */
1593#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001594#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001595#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001596#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001598#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599#endif /* LINUX */
1600#ifdef SUNOS4
1601 /* get error code from user struct */
1602 if (upeek(pid, uoff(u_error), &u_error) < 0)
1603 return -1;
1604 u_error >>= 24; /* u_error is a char */
1605
1606 /* get system call return value */
1607 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1608 return -1;
1609#endif /* SUNOS4 */
1610#ifdef SVR4
1611#ifdef SPARC
1612 /* Judicious guessing goes a long way. */
1613 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1614 tcp->u_rval = -1;
1615 u_error = tcp->status.pr_reg[R_O0];
1616 }
1617 else {
1618 tcp->u_rval = tcp->status.pr_reg[R_O0];
1619 u_error = 0;
1620 }
1621#endif /* SPARC */
1622#ifdef I386
1623 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001624 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001626 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 }
1628 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001629 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001630#ifdef HAVE_LONG_LONG
1631 tcp->u_lrval =
1632 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1633 tcp->status.PR_REG[EAX];
1634#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635 u_error = 0;
1636 }
1637#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001638#ifdef X86_64
1639 /* Wanna know how to kill an hour single-stepping? */
1640 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1641 tcp->u_rval = -1;
1642 u_error = tcp->status.PR_REG[RAX];
1643 }
1644 else {
1645 tcp->u_rval = tcp->status.PR_REG[RAX];
1646 u_error = 0;
1647 }
1648#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649#ifdef MIPS
1650 if (tcp->status.pr_reg[CTX_A3]) {
1651 tcp->u_rval = -1;
1652 u_error = tcp->status.pr_reg[CTX_V0];
1653 }
1654 else {
1655 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1656 u_error = 0;
1657 }
1658#endif /* MIPS */
1659#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001660#ifdef FREEBSD
1661 if (regs.r_eflags & PSL_C) {
1662 tcp->u_rval = -1;
1663 u_error = regs.r_eax;
1664 } else {
1665 tcp->u_rval = regs.r_eax;
1666 tcp->u_lrval =
1667 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1668 u_error = 0;
1669 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001670#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001671 tcp->u_error = u_error;
1672 return 1;
1673}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674
Roland McGrathb69f81b2002-12-21 23:25:18 +00001675int
1676force_result(tcp, error, rval)
1677 struct tcb *tcp;
1678 int error;
1679 long rval;
1680{
1681#ifdef LINUX
1682#if defined(S390) || defined(S390X)
1683 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001684 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1685 return -1;
1686#else /* !S390 && !S390X */
1687#ifdef I386
1688 eax = error ? -error : rval;
1689 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1690 return -1;
1691#else /* !I386 */
1692#ifdef X86_64
1693 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001694 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001695 return -1;
1696#else
1697#ifdef IA64
1698 if (ia32) {
1699 r8 = error ? -error : rval;
1700 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1701 return -1;
1702 }
1703 else {
1704 if (error) {
1705 r8 = error;
1706 r10 = -1;
1707 }
1708 else {
1709 r8 = rval;
1710 r10 = 0;
1711 }
1712 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1713 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1714 return -1;
1715 }
1716#else /* !IA64 */
1717#ifdef MIPS
1718 if (error) {
1719 r2 = error;
1720 a3 = -1;
1721 }
1722 else {
1723 r2 = rval;
1724 a3 = 0;
1725 }
1726 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1727 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1728 return -1;
1729#else
1730#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001731 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001732 return -1;
1733 if (error) {
1734 flags |= SO_MASK;
1735 result = error;
1736 }
1737 else {
1738 flags &= ~SO_MASK;
1739 result = rval;
1740 }
Roland McGratheb285352003-01-14 09:59:00 +00001741 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1742 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001743 return -1;
1744#else /* !POWERPC */
1745#ifdef M68K
1746 d0 = error ? -error : rval;
1747 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1748 return -1;
1749#else /* !M68K */
1750#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001751 regs.ARM_r0 = error ? -error : rval;
1752 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001753 return -1;
1754#else /* !ARM */
1755#ifdef ALPHA
1756 if (error) {
1757 a3 = -1;
1758 r0 = error;
1759 }
1760 else {
1761 a3 = 0;
1762 r0 = rval;
1763 }
1764 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1765 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1766 return -1;
1767#else /* !ALPHA */
1768#ifdef SPARC
1769 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1770 return -1;
1771 if (error) {
1772 regs.r_psr |= PSR_C;
1773 regs.r_o0 = error;
1774 }
1775 else {
1776 regs.r_psr &= ~PSR_C;
1777 regs.r_o0 = rval;
1778 }
1779 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1780 return -1;
1781#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001782#ifdef SPARC64
1783 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1784 return -1;
1785 if (error) {
1786 regs.r_tstate |= 0x1100000000UL;
1787 regs.r_o0 = error;
1788 }
1789 else {
1790 regs.r_tstate &= ~0x1100000000UL;
1791 regs.r_o0 = rval;
1792 }
1793 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1794 return -1;
1795#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796#ifdef HPPA
1797 r28 = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1799 return -1;
1800#else
1801#ifdef SH
1802 r0 = error ? -error : rval;
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1804 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001805#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001806#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001807 r9 = error ? -error : rval;
1808 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1809 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001810#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001811#endif /* SH */
1812#endif /* HPPA */
1813#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001814#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001815#endif /* ALPHA */
1816#endif /* ARM */
1817#endif /* M68K */
1818#endif /* POWERPC */
1819#endif /* MIPS */
1820#endif /* IA64 */
1821#endif /* X86_64 */
1822#endif /* I386 */
1823#endif /* S390 || S390X */
1824#endif /* LINUX */
1825#ifdef SUNOS4
1826 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1827 error << 24) < 0 ||
1828 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1829 return -1;
1830#endif /* SUNOS4 */
1831#ifdef SVR4
1832 /* XXX no clue */
1833 return -1;
1834#endif /* SVR4 */
1835#ifdef FREEBSD
1836 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1837 perror("pread");
1838 return -1;
1839 }
1840 if (error) {
1841 regs.r_eflags |= PSL_C;
1842 regs.r_eax = error;
1843 }
1844 else {
1845 regs.r_eflags &= ~PSL_C;
1846 regs.r_eax = rval;
1847 }
1848 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1849 perror("pwrite");
1850 return -1;
1851 }
1852#endif /* FREEBSD */
1853
1854 /* All branches reach here on success (only). */
1855 tcp->u_error = error;
1856 tcp->u_rval = rval;
1857 return 0;
1858}
1859
Roland McGratha4d48532005-06-08 20:45:28 +00001860static int
1861syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001862struct tcb *tcp;
1863{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001864#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001865 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001866#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001867#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001868#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001869 {
1870 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001871 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1872 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001873 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001874 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001875 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001876 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001877 return -1;
1878 }
1879 }
1880#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001881 {
1882 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001883 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1884 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001885 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001886 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001888 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1889 * for scno somewhere above here!
1890 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1892 return -1;
1893 }
1894 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001895#elif defined (IA64)
1896 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001897 if (!ia32) {
1898 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1899 /* be backwards compatible with kernel < 2.4.4... */
1900# ifndef PT_RBS_END
1901# define PT_RBS_END PT_AR_BSP
1902# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001903
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001904 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001905 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001906 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1907 return -1;
1908
1909 sof = (cfm >> 0) & 0x7f;
1910 sol = (cfm >> 7) & 0x7f;
1911 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1912
1913 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1914 && sysent[tcp->scno].nargs != -1)
1915 tcp->u_nargs = sysent[tcp->scno].nargs;
1916 else
1917 tcp->u_nargs = MAX_ARGS;
1918 for (i = 0; i < tcp->u_nargs; ++i) {
1919 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1920 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1921 return -1;
1922 }
1923 } else {
1924 int i;
1925
1926 if (/* EBX = out0 */
1927 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1928 /* ECX = out1 */
1929 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1930 /* EDX = out2 */
1931 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1932 /* ESI = out3 */
1933 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1934 /* EDI = out4 */
1935 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1936 /* EBP = out5 */
1937 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1938 return -1;
1939
1940 for (i = 0; i < 6; ++i)
1941 /* truncate away IVE sign-extension */
1942 tcp->u_arg[i] &= 0xffffffff;
1943
1944 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1945 && sysent[tcp->scno].nargs != -1)
1946 tcp->u_nargs = sysent[tcp->scno].nargs;
1947 else
1948 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001949 }
1950 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001951#elif defined (MIPS)
1952 {
1953 long sp;
1954 int i, nargs;
1955
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001956 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1957 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001958 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001960 if(nargs > 4) {
1961 if(upeek(pid, REG_SP, &sp) < 0)
1962 return -1;
1963 for(i = 0; i < 4; i++) {
1964 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1965 return -1;
1966 }
1967 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1968 (char *)(tcp->u_arg + 4));
1969 } else {
1970 for(i = 0; i < nargs; i++) {
1971 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1972 return -1;
1973 }
1974 }
1975 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00001977#ifndef PT_ORIG_R3
1978#define PT_ORIG_R3 34
1979#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980 {
1981 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001982 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1983 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001984 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001985 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001986 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00001987 if (upeek(pid, (i==0) ?
1988 (sizeof(unsigned long)*PT_ORIG_R3) :
1989 ((i+PT_R3)*sizeof(unsigned long)),
1990 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001991 return -1;
1992 }
1993 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001994#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001996 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001997
1998 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1999 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002000 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002001 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002003 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002004 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002005#elif defined (HPPA)
2006 {
2007 int i;
2008
2009 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2010 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002011 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002012 tcp->u_nargs = MAX_ARGS;
2013 for (i = 0; i < tcp->u_nargs; i++) {
2014 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2015 return -1;
2016 }
2017 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002018#elif defined(ARM)
2019 {
2020 int i;
2021
2022 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2023 tcp->u_nargs = sysent[tcp->scno].nargs;
2024 else
2025 tcp->u_nargs = MAX_ARGS;
2026 for (i = 0; i < tcp->u_nargs; i++)
2027 tcp->u_arg[i] = regs.uregs[i];
2028 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002029#elif defined(SH)
2030 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002031 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002032 static int syscall_regs[] = {
2033 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2034 REG_REG0, REG_REG0+1, REG_REG0+2
2035 };
2036
2037 tcp->u_nargs = sysent[tcp->scno].nargs;
2038 for (i = 0; i < tcp->u_nargs; i++) {
2039 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2040 return -1;
2041 }
2042 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002043#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002044 {
2045 int i;
2046 /* Registers used by SH5 Linux system calls for parameters */
2047 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2048
2049 /*
2050 * TODO: should also check that the number of arguments encoded
2051 * in the trap number matches the number strace expects.
2052 */
2053 /*
2054 assert(sysent[tcp->scno].nargs <
2055 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2056 */
2057
2058 tcp->u_nargs = sysent[tcp->scno].nargs;
2059 for (i = 0; i < tcp->u_nargs; i++) {
2060 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2061 return -1;
2062 }
2063 }
2064
Michal Ludvig0e035502002-09-23 15:41:01 +00002065#elif defined(X86_64)
2066 {
2067 int i;
2068 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2069 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002070 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002071 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002072
Michal Ludvig0e035502002-09-23 15:41:01 +00002073 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2074 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002075 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002076 tcp->u_nargs = MAX_ARGS;
2077 for (i = 0; i < tcp->u_nargs; i++) {
2078 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2079 return -1;
2080 }
2081 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002082#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002083 {
2084 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002085 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2086 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002087 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002088 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089 for (i = 0; i < tcp->u_nargs; i++) {
2090 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2091 return -1;
2092 }
2093 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002094#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095#endif /* LINUX */
2096#ifdef SUNOS4
2097 {
2098 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2100 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002101 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002102 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 for (i = 0; i < tcp->u_nargs; i++) {
2104 struct user *u;
2105
2106 if (upeek(pid, uoff(u_arg[0]) +
2107 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2108 return -1;
2109 }
2110 }
2111#endif /* SUNOS4 */
2112#ifdef SVR4
2113#ifdef MIPS
2114 /*
2115 * SGI is broken: even though it has pr_sysarg, it doesn't
2116 * set them on system call entry. Get a clue.
2117 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002118 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 tcp->u_nargs = sysent[tcp->scno].nargs;
2120 else
2121 tcp->u_nargs = tcp->status.pr_nsysarg;
2122 if (tcp->u_nargs > 4) {
2123 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2124 4*sizeof(tcp->u_arg[0]));
2125 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2126 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2127 }
2128 else {
2129 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2130 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2131 }
John Hughes25299712001-03-06 10:10:06 +00002132#elif UNIXWARE >= 2
2133 /*
2134 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2135 */
2136 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
2138 else
2139 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2140 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2141 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2142#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002143 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144 tcp->u_nargs = sysent[tcp->scno].nargs;
2145 else
2146 tcp->u_nargs = tcp->status.pr_nsysarg;
2147 {
2148 int i;
2149 for (i = 0; i < tcp->u_nargs; i++)
2150 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2151 }
John Hughes25299712001-03-06 10:10:06 +00002152#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002153 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002154 tcp->u_nargs = sysent[tcp->scno].nargs;
2155 else
2156 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002157 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002159#else
2160 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002162#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002163#ifdef FREEBSD
2164 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2165 sysent[tcp->scno].nargs > tcp->status.val)
2166 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002167 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002168 tcp->u_nargs = tcp->status.val;
2169 if (tcp->u_nargs < 0)
2170 tcp->u_nargs = 0;
2171 if (tcp->u_nargs > MAX_ARGS)
2172 tcp->u_nargs = MAX_ARGS;
2173 switch(regs.r_eax) {
2174 case SYS___syscall:
2175 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2176 regs.r_esp + sizeof(int) + sizeof(quad_t));
2177 break;
2178 case SYS_syscall:
2179 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2180 regs.r_esp + 2 * sizeof(int));
2181 break;
2182 default:
2183 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2184 regs.r_esp + sizeof(int));
2185 break;
2186 }
2187#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002188 return 1;
2189}
2190
2191int
2192trace_syscall(tcp)
2193struct tcb *tcp;
2194{
2195 int sys_res;
2196 struct timeval tv;
2197 int res;
2198
2199 /* Measure the exit time as early as possible to avoid errors. */
2200 if (dtime && (tcp->flags & TCB_INSYSCALL))
2201 gettimeofday(&tv, NULL);
2202
2203 res = get_scno(tcp);
2204 if (res != 1)
2205 return res;
2206
2207 res = syscall_fixup(tcp);
2208 if (res != 1)
2209 return res;
2210
2211 if (tcp->flags & TCB_INSYSCALL) {
2212 long u_error;
2213 res = get_error(tcp);
2214 if (res != 1)
2215 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002216
2217 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002218 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2219 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002220 tcp->flags &= ~TCB_INSYSCALL;
2221 return 0;
2222 }
2223
2224 if (tcp->flags & TCB_REPRINT) {
2225 printleader(tcp);
2226 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002227 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002228 tprintf("syscall_%lu", tcp->scno);
2229 else
2230 tprintf("%s", sysent[tcp->scno].sys_name);
2231 tprintf(" resumed> ");
2232 }
2233
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002235 if (counts == NULL) {
2236 counts = calloc(sizeof *counts, nsyscalls);
2237 if (counts == NULL) {
2238 fprintf(stderr, "\
2239strace: out of memory for call counts\n");
2240 exit(1);
2241 }
2242 }
2243
2244 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002245 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002246 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002247 tv_sub(&tv, &tv, &tcp->etime);
2248#ifdef LINUX
2249 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002250 static struct timeval one_tick;
2251 if (one_tick.tv_usec == 0) {
2252 /* Initialize it. */
2253 struct itimerval it;
2254 memset(&it, 0, sizeof it);
2255 it.it_interval.tv_usec = 1;
2256 setitimer(ITIMER_REAL, &it, NULL);
2257 getitimer(ITIMER_REAL, &it);
2258 one_tick = it.it_interval;
2259 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002260
2261 if (tv_nz(&tcp->dtime))
2262 tv = tcp->dtime;
2263 else if (tv_cmp(&tv, &one_tick) > 0) {
2264 if (tv_cmp(&shortest, &one_tick) < 0)
2265 tv = shortest;
2266 else
2267 tv = one_tick;
2268 }
2269 }
2270#endif /* LINUX */
2271 if (tv_cmp(&tv, &shortest) < 0)
2272 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002273 tv_add(&counts[tcp->scno].time,
2274 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002275 tcp->flags &= ~TCB_INSYSCALL;
2276 return 0;
2277 }
2278
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002279 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002280 || (qual_flags[tcp->scno] & QUAL_RAW))
2281 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002282 else {
2283 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002284 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002285 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002286 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002287 u_error = tcp->u_error;
2288 tprintf(") ");
2289 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002290 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2291 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002292 if (u_error)
2293 tprintf("= -1 (errno %ld)", u_error);
2294 else
2295 tprintf("= %#lx", tcp->u_rval);
2296 }
2297 else if (!(sys_res & RVAL_NONE) && u_error) {
2298 switch (u_error) {
2299#ifdef LINUX
2300 case ERESTARTSYS:
2301 tprintf("= ? ERESTARTSYS (To be restarted)");
2302 break;
2303 case ERESTARTNOINTR:
2304 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2305 break;
2306 case ERESTARTNOHAND:
2307 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2308 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002309 case ERESTART_RESTARTBLOCK:
2310 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2311 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002312#endif /* LINUX */
2313 default:
2314 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002315 if (u_error < 0)
2316 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002317 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002318 tprintf("%s (%s)", errnoent[u_error],
2319 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002320 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002321 tprintf("ERRNO_%ld (%s)", u_error,
2322 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002323 break;
2324 }
2325 }
2326 else {
2327 if (sys_res & RVAL_NONE)
2328 tprintf("= ?");
2329 else {
2330 switch (sys_res & RVAL_MASK) {
2331 case RVAL_HEX:
2332 tprintf("= %#lx", tcp->u_rval);
2333 break;
2334 case RVAL_OCTAL:
2335 tprintf("= %#lo", tcp->u_rval);
2336 break;
2337 case RVAL_UDECIMAL:
2338 tprintf("= %lu", tcp->u_rval);
2339 break;
2340 case RVAL_DECIMAL:
2341 tprintf("= %ld", tcp->u_rval);
2342 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002343#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002344 case RVAL_LHEX:
2345 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002346 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002347 case RVAL_LOCTAL:
2348 tprintf("= %#llo", tcp->u_lrval);
2349 break;
2350 case RVAL_LUDECIMAL:
2351 tprintf("= %llu", tcp->u_lrval);
2352 break;
2353 case RVAL_LDECIMAL:
2354 tprintf("= %lld", tcp->u_lrval);
2355 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002356#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002357 default:
2358 fprintf(stderr,
2359 "invalid rval format\n");
2360 break;
2361 }
2362 }
2363 if ((sys_res & RVAL_STR) && tcp->auxstr)
2364 tprintf(" (%s)", tcp->auxstr);
2365 }
2366 if (dtime) {
2367 tv_sub(&tv, &tv, &tcp->etime);
2368 tprintf(" <%ld.%06ld>",
2369 (long) tv.tv_sec, (long) tv.tv_usec);
2370 }
2371 printtrailer(tcp);
2372
2373 dumpio(tcp);
2374 if (fflush(tcp->outf) == EOF)
2375 return -1;
2376 tcp->flags &= ~TCB_INSYSCALL;
2377 return 0;
2378 }
2379
2380 /* Entering system call */
2381 res = syscall_enter(tcp);
2382 if (res != 1)
2383 return res;
2384
Roland McGrath17352792005-06-07 23:21:26 +00002385 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002386#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002387#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002388 case SYS_socketcall:
2389 decode_subcall(tcp, SYS_socket_subcall,
2390 SYS_socket_nsubcalls, deref_style);
2391 break;
2392 case SYS_ipc:
2393 decode_subcall(tcp, SYS_ipc_subcall,
2394 SYS_ipc_nsubcalls, shift_style);
2395 break;
Roland McGrath17352792005-06-07 23:21:26 +00002396#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002397#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002398 case SYS_socketcall:
2399 sparc_socket_decode (tcp);
2400 break;
2401#endif
2402#endif /* LINUX */
2403#ifdef SVR4
2404#ifdef SYS_pgrpsys_subcall
2405 case SYS_pgrpsys:
2406 decode_subcall(tcp, SYS_pgrpsys_subcall,
2407 SYS_pgrpsys_nsubcalls, shift_style);
2408 break;
2409#endif /* SYS_pgrpsys_subcall */
2410#ifdef SYS_sigcall_subcall
2411 case SYS_sigcall:
2412 decode_subcall(tcp, SYS_sigcall_subcall,
2413 SYS_sigcall_nsubcalls, mask_style);
2414 break;
2415#endif /* SYS_sigcall_subcall */
2416 case SYS_msgsys:
2417 decode_subcall(tcp, SYS_msgsys_subcall,
2418 SYS_msgsys_nsubcalls, shift_style);
2419 break;
2420 case SYS_shmsys:
2421 decode_subcall(tcp, SYS_shmsys_subcall,
2422 SYS_shmsys_nsubcalls, shift_style);
2423 break;
2424 case SYS_semsys:
2425 decode_subcall(tcp, SYS_semsys_subcall,
2426 SYS_semsys_nsubcalls, shift_style);
2427 break;
2428#if 0 /* broken */
2429 case SYS_utssys:
2430 decode_subcall(tcp, SYS_utssys_subcall,
2431 SYS_utssys_nsubcalls, shift_style);
2432 break;
2433#endif
2434 case SYS_sysfs:
2435 decode_subcall(tcp, SYS_sysfs_subcall,
2436 SYS_sysfs_nsubcalls, shift_style);
2437 break;
2438 case SYS_spcall:
2439 decode_subcall(tcp, SYS_spcall_subcall,
2440 SYS_spcall_nsubcalls, shift_style);
2441 break;
2442#ifdef SYS_context_subcall
2443 case SYS_context:
2444 decode_subcall(tcp, SYS_context_subcall,
2445 SYS_context_nsubcalls, shift_style);
2446 break;
2447#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002448#ifdef SYS_door_subcall
2449 case SYS_door:
2450 decode_subcall(tcp, SYS_door_subcall,
2451 SYS_door_nsubcalls, door_style);
2452 break;
2453#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002454#ifdef SYS_kaio_subcall
2455 case SYS_kaio:
2456 decode_subcall(tcp, SYS_kaio_subcall,
2457 SYS_kaio_nsubcalls, shift_style);
2458 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002459#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002460#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002461#ifdef FREEBSD
2462 case SYS_msgsys:
2463 case SYS_shmsys:
2464 case SYS_semsys:
2465 decode_subcall(tcp, 0, 0, table_style);
2466 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002467#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002468#ifdef SUNOS4
2469 case SYS_semsys:
2470 decode_subcall(tcp, SYS_semsys_subcall,
2471 SYS_semsys_nsubcalls, shift_style);
2472 break;
2473 case SYS_msgsys:
2474 decode_subcall(tcp, SYS_msgsys_subcall,
2475 SYS_msgsys_nsubcalls, shift_style);
2476 break;
2477 case SYS_shmsys:
2478 decode_subcall(tcp, SYS_shmsys_subcall,
2479 SYS_shmsys_nsubcalls, shift_style);
2480 break;
2481#endif
2482 }
2483
2484 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002485 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002486 tcp->flags |= TCB_INSYSCALL;
2487 return 0;
2488 }
2489
2490 if (cflag) {
2491 gettimeofday(&tcp->etime, NULL);
2492 tcp->flags |= TCB_INSYSCALL;
2493 return 0;
2494 }
2495
2496 printleader(tcp);
2497 tcp->flags &= ~TCB_REPRINT;
2498 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002499 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002500 tprintf("syscall_%lu(", tcp->scno);
2501 else
2502 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002503 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002504 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2505 sys_res = printargs(tcp);
2506 else
2507 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2508 if (fflush(tcp->outf) == EOF)
2509 return -1;
2510 tcp->flags |= TCB_INSYSCALL;
2511 /* Measure the entrance time as late as possible to avoid errors. */
2512 if (dtime)
2513 gettimeofday(&tcp->etime, NULL);
2514 return sys_res;
2515}
2516
2517int
2518printargs(tcp)
2519struct tcb *tcp;
2520{
2521 if (entering(tcp)) {
2522 int i;
2523
2524 for (i = 0; i < tcp->u_nargs; i++)
2525 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2526 }
2527 return 0;
2528}
2529
2530long
2531getrval2(tcp)
2532struct tcb *tcp;
2533{
2534 long val = -1;
2535
2536#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002537#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002538 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002539 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2540 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002541 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002542#elif defined(SH)
2543 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2544 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002545#elif defined(IA64)
2546 if (upeek(tcp->pid, PT_R9, &val) < 0)
2547 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002548#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002549#endif /* LINUX */
2550
2551#ifdef SUNOS4
2552 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2553 return -1;
2554#endif /* SUNOS4 */
2555
2556#ifdef SVR4
2557#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002558 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559#endif /* SPARC */
2560#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002561 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002562#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002563#ifdef X86_64
2564 val = tcp->status.PR_REG[RDX];
2565#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002567 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002568#endif /* MIPS */
2569#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002570#ifdef FREEBSD
2571 struct reg regs;
2572 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2573 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002574#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575 return val;
2576}
2577
2578/*
2579 * Apparently, indirect system calls have already be converted by ptrace(2),
2580 * so if you see "indir" this program has gone astray.
2581 */
2582int
2583sys_indir(tcp)
2584struct tcb *tcp;
2585{
2586 int i, scno, nargs;
2587
2588 if (entering(tcp)) {
2589 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2590 fprintf(stderr, "Bogus syscall: %u\n", scno);
2591 return 0;
2592 }
2593 nargs = sysent[scno].nargs;
2594 tprintf("%s", sysent[scno].sys_name);
2595 for (i = 0; i < nargs; i++)
2596 tprintf(", %#lx", tcp->u_arg[i+1]);
2597 }
2598 return 0;
2599}
2600
2601static int
2602time_cmp(a, b)
2603void *a;
2604void *b;
2605{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002606 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607}
2608
2609static int
2610syscall_cmp(a, b)
2611void *a;
2612void *b;
2613{
2614 return strcmp(sysent[*((int *) a)].sys_name,
2615 sysent[*((int *) b)].sys_name);
2616}
2617
2618static int
2619count_cmp(a, b)
2620void *a;
2621void *b;
2622{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002623 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002624
2625 return (m < n) ? 1 : (m > n) ? -1 : 0;
2626}
2627
2628static int (*sortfun)();
2629static struct timeval overhead = { -1, -1 };
2630
2631void
2632set_sortby(sortby)
2633char *sortby;
2634{
2635 if (strcmp(sortby, "time") == 0)
2636 sortfun = time_cmp;
2637 else if (strcmp(sortby, "calls") == 0)
2638 sortfun = count_cmp;
2639 else if (strcmp(sortby, "name") == 0)
2640 sortfun = syscall_cmp;
2641 else if (strcmp(sortby, "nothing") == 0)
2642 sortfun = NULL;
2643 else {
2644 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2645 exit(1);
2646 }
2647}
2648
2649void set_overhead(n)
2650int n;
2651{
2652 overhead.tv_sec = n / 1000000;
2653 overhead.tv_usec = n % 1000000;
2654}
2655
2656void
2657call_summary(outf)
2658FILE *outf;
2659{
2660 int i, j;
2661 int call_cum, error_cum;
2662 struct timeval tv_cum, dtv;
2663 double percent;
2664 char *dashes = "-------------------------";
2665 char error_str[16];
2666
Roland McGrathe10e62a2004-09-04 04:20:43 +00002667 int *sorted_count = malloc(nsyscalls * sizeof(int));
2668
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2670 if (overhead.tv_sec == -1) {
2671 tv_mul(&overhead, &shortest, 8);
2672 tv_div(&overhead, &overhead, 10);
2673 }
2674 for (i = 0; i < nsyscalls; i++) {
2675 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002676 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002678 tv_mul(&dtv, &overhead, counts[i].calls);
2679 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2680 call_cum += counts[i].calls;
2681 error_cum += counts[i].errors;
2682 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002684 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002685 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2686 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2687 "% time", "seconds", "usecs/call",
2688 "calls", "errors", "syscall");
2689 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2690 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002691 if (counts) {
2692 for (i = 0; i < nsyscalls; i++) {
2693 j = sorted_count[i];
2694 if (counts[j].calls == 0)
2695 continue;
2696 tv_div(&dtv, &counts[j].time, counts[j].calls);
2697 if (counts[j].errors)
2698 sprintf(error_str, "%d", counts[j].errors);
2699 else
2700 error_str[0] = '\0';
2701 percent = (100.0 * tv_float(&counts[j].time)
2702 / tv_float(&tv_cum));
2703 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2704 percent, (long) counts[j].time.tv_sec,
2705 (long) counts[j].time.tv_usec,
2706 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2707 counts[j].calls,
2708 error_str, sysent[j].sys_name);
2709 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002711 free(sorted_count);
2712
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2714 dashes, dashes, dashes, dashes, dashes, dashes);
2715 if (error_cum)
2716 sprintf(error_str, "%d", error_cum);
2717 else
2718 error_str[0] = '\0';
2719 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2720 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2721 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002722
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002723}