blob: c84a3dee4efdcbdee501c6c19f9531e774ce3d85 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
133#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000134static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135#include "syscallent1.h"
136};
Roland McGrathee36ce12004-09-04 03:53:10 +0000137static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138#endif /* SUPPORTED_PERSONALITIES >= 2 */
139
140#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000141static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142#include "syscallent2.h"
143};
Roland McGrathee36ce12004-09-04 03:53:10 +0000144static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145#endif /* SUPPORTED_PERSONALITIES >= 3 */
146
Roland McGrathee36ce12004-09-04 03:53:10 +0000147const struct sysent *sysent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148int nsyscalls;
149
150/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000151#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152#undef TF
153#undef TI
154#undef TN
155#undef TP
156#undef TS
157
Roland McGrathee36ce12004-09-04 03:53:10 +0000158static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000159#include "errnoent.h"
160};
Roland McGrathee36ce12004-09-04 03:53:10 +0000161static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000162
163#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000164static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165#include "errnoent1.h"
166};
Roland McGrathee36ce12004-09-04 03:53:10 +0000167static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000168#endif /* SUPPORTED_PERSONALITIES >= 2 */
169
170#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#include "errnoent2.h"
173};
Roland McGrathee36ce12004-09-04 03:53:10 +0000174static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175#endif /* SUPPORTED_PERSONALITIES >= 3 */
176
Roland McGrathee36ce12004-09-04 03:53:10 +0000177const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000178int nerrnos;
179
180int current_personality;
181
182int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000183set_personality(personality)
184int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185{
186 switch (personality) {
187 case 0:
188 errnoent = errnoent0;
189 nerrnos = nerrnos0;
190 sysent = sysent0;
191 nsyscalls = nsyscalls0;
192 ioctlent = ioctlent0;
193 nioctlents = nioctlents0;
194 signalent = signalent0;
195 nsignals = nsignals0;
196 break;
197
198#if SUPPORTED_PERSONALITIES >= 2
199 case 1:
200 errnoent = errnoent1;
201 nerrnos = nerrnos1;
202 sysent = sysent1;
203 nsyscalls = nsyscalls1;
204 ioctlent = ioctlent1;
205 nioctlents = nioctlents1;
206 signalent = signalent1;
207 nsignals = nsignals1;
208 break;
209#endif /* SUPPORTED_PERSONALITIES >= 2 */
210
211#if SUPPORTED_PERSONALITIES >= 3
212 case 2:
213 errnoent = errnoent2;
214 nerrnos = nerrnos2;
215 sysent = sysent2;
216 nsyscalls = nsyscalls2;
217 ioctlent = ioctlent2;
218 nioctlents = nioctlents2;
219 signalent = signalent2;
220 nsignals = nsignals2;
221 break;
222#endif /* SUPPORTED_PERSONALITIES >= 3 */
223
224 default:
225 return -1;
226 }
227
228 current_personality = personality;
229 return 0;
230}
231
232int qual_flags[MAX_QUALS];
233
Roland McGrathe10e62a2004-09-04 04:20:43 +0000234
235struct call_counts {
236 struct timeval time;
237 int calls, errors;
238};
239
240static struct call_counts *counts;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241
242static struct timeval shortest = { 1000000, 0 };
243
Roland McGrath9797ceb2002-12-30 10:23:00 +0000244static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000245
Roland McGrathe10e62a2004-09-04 04:20:43 +0000246static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000247 int bitflag;
248 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000249 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250 char *argument_name;
251} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252 { QUAL_TRACE, "trace", qual_syscall, "system call" },
253 { QUAL_TRACE, "t", qual_syscall, "system call" },
254 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
255 { QUAL_ABBREV, "a", qual_syscall, "system call" },
256 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
257 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
258 { QUAL_RAW, "raw", qual_syscall, "system call" },
259 { QUAL_RAW, "x", qual_syscall, "system call" },
260 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
261 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
262 { QUAL_SIGNAL, "s", qual_signal, "signal" },
263 { QUAL_FAULT, "fault", qual_fault, "fault" },
264 { QUAL_FAULT, "faults", qual_fault, "fault" },
265 { QUAL_FAULT, "m", qual_fault, "fault" },
266 { QUAL_READ, "read", qual_desc, "descriptor" },
267 { QUAL_READ, "reads", qual_desc, "descriptor" },
268 { QUAL_READ, "r", qual_desc, "descriptor" },
269 { QUAL_WRITE, "write", qual_desc, "descriptor" },
270 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
271 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272 { 0, NULL, NULL, NULL },
273};
274
Roland McGrath9797ceb2002-12-30 10:23:00 +0000275static void
276qualify_one(n, opt, not)
277 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000278 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000279 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280{
Roland McGrath9797ceb2002-12-30 10:23:00 +0000281 if (not)
282 qual_flags[n] &= ~opt->bitflag;
283 else
284 qual_flags[n] |= opt->bitflag;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000285}
286
287static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000288qual_syscall(s, opt, not)
289 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000290 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000291 int not;
292{
293 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000294 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000295
Roland McGrath48a035f2006-01-12 09:45:56 +0000296 if (isdigit((unsigned char)*s)) {
297 int i = atoi(s);
298 if (i < 0 || i >= nsyscalls)
299 return -1;
300 qualify_one(i, opt, not);
301 return 0;
302 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000303 for (i = 0; i < nsyscalls; i++) {
304 if (strcmp(s, sysent[i].sys_name) == 0) {
305 qualify_one(i, opt, not);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000306 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000307 }
308 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000309 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000310}
311
312static int
313qual_signal(s, opt, not)
314 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000315 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000316 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000317{
318 int i;
319 char buf[32];
320
Roland McGrath48a035f2006-01-12 09:45:56 +0000321 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000322 int signo = atoi(s);
323 if (signo < 0 || signo >= MAX_QUALS)
324 return -1;
325 qualify_one(signo, opt, not);
326 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000327 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000328 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000329 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000330 strcpy(buf, s);
331 s = buf;
332 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000333 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000334 if (strncmp(s, "SIG", 3) == 0)
335 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 for (i = 0; i <= NSIG; i++)
337 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath76421df2005-02-02 03:51:18 +0000338 qualify_one(i, opt, not);
339 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000340 }
Roland McGrath76421df2005-02-02 03:51:18 +0000341 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000342}
343
344static int
345qual_fault(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 return -1;
351}
352
353static int
354qual_desc(s, opt, not)
355 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000356 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000357 int not;
358{
Roland McGrath48a035f2006-01-12 09:45:56 +0000359 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000360 int desc = atoi(s);
361 if (desc < 0 || desc >= MAX_QUALS)
362 return -1;
363 qualify_one(desc, opt, not);
Roland McGrath2b619022003-04-10 18:58:20 +0000364 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000365 }
366 return -1;
367}
368
369static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000370lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000371 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000372{
373 if (strcmp(s, "file") == 0)
374 return TRACE_FILE;
375 if (strcmp(s, "ipc") == 0)
376 return TRACE_IPC;
377 if (strcmp(s, "network") == 0)
378 return TRACE_NETWORK;
379 if (strcmp(s, "process") == 0)
380 return TRACE_PROCESS;
381 if (strcmp(s, "signal") == 0)
382 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000383 if (strcmp(s, "desc") == 0)
384 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385 return -1;
386}
387
388void
389qualify(s)
390char *s;
391{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 int not;
394 char *p;
395 int i, n;
396
397 opt = &qual_options[0];
398 for (i = 0; (p = qual_options[i].option_name); i++) {
399 n = strlen(p);
400 if (strncmp(s, p, n) == 0 && s[n] == '=') {
401 opt = &qual_options[i];
402 s += n + 1;
403 break;
404 }
405 }
406 not = 0;
407 if (*s == '!') {
408 not = 1;
409 s++;
410 }
411 if (strcmp(s, "none") == 0) {
412 not = 1 - not;
413 s = "all";
414 }
415 if (strcmp(s, "all") == 0) {
416 for (i = 0; i < MAX_QUALS; i++) {
417 if (not)
418 qual_flags[i] &= ~opt->bitflag;
419 else
420 qual_flags[i] |= opt->bitflag;
421 }
422 return;
423 }
424 for (i = 0; i < MAX_QUALS; i++) {
425 if (not)
426 qual_flags[i] |= opt->bitflag;
427 else
428 qual_flags[i] &= ~opt->bitflag;
429 }
430 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
431 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
432 for (i = 0; i < MAX_QUALS; i++) {
433 if (sysent[i].sys_flags & n) {
434 if (not)
435 qual_flags[i] &= ~opt->bitflag;
436 else
437 qual_flags[i] |= opt->bitflag;
438 }
439 }
440 continue;
441 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000442 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443 fprintf(stderr, "strace: invalid %s `%s'\n",
444 opt->argument_name, p);
445 exit(1);
446 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000447 }
448 return;
449}
450
451static void
452dumpio(tcp)
453struct tcb *tcp;
454{
455 if (syserror(tcp))
456 return;
457 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
458 return;
Roland McGrath17352792005-06-07 23:21:26 +0000459 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000461#ifdef SYS_pread64
462 case SYS_pread64:
463#endif
464#if defined SYS_pread && SYS_pread64 != SYS_pread
465 case SYS_pread:
466#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467#ifdef SYS_recv
468 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000469#elif defined SYS_sub_recv
470 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471#endif
472#ifdef SYS_recvfrom
473 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000474#elif defined SYS_sub_recvfrom
475 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000476#endif
477 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
478 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
479 break;
480 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000481#ifdef SYS_pwrite64
482 case SYS_pwrite64:
483#endif
484#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
485 case SYS_pwrite:
486#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487#ifdef SYS_send
488 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000489#elif defined SYS_sub_send
490 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491#endif
492#ifdef SYS_sendto
493 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000494#elif defined SYS_sub_sendto
495 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496#endif
497 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
498 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
499 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000500#ifdef SYS_readv
501 case SYS_readv:
502 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
503 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
504 break;
505#endif
506#ifdef SYS_writev
507 case SYS_writev:
508
509 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
510 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
511 break;
512#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513 }
514}
515
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000516#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000517enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000518#else /* FREEBSD */
519enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
520
521struct subcall {
522 int call;
523 int nsubcalls;
524 int subcalls[5];
525};
526
Roland McGratha4d48532005-06-08 20:45:28 +0000527static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000528 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000529#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000530 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000531#else
532 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
533#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000534 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
535};
536#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000538#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539
Roland McGratha4d48532005-06-08 20:45:28 +0000540static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 /* SYS_SOCKET */ 97,
542 /* SYS_BIND */ 104,
543 /* SYS_CONNECT */ 98,
544 /* SYS_LISTEN */ 106,
545 /* SYS_ACCEPT */ 99,
546 /* SYS_GETSOCKNAME */ 150,
547 /* SYS_GETPEERNAME */ 141,
548 /* SYS_SOCKETPAIR */ 135,
549 /* SYS_SEND */ 101,
550 /* SYS_RECV */ 102,
551 /* SYS_SENDTO */ 133,
552 /* SYS_RECVFROM */ 125,
553 /* SYS_SHUTDOWN */ 134,
554 /* SYS_SETSOCKOPT */ 105,
555 /* SYS_GETSOCKOPT */ 118,
556 /* SYS_SENDMSG */ 114,
557 /* SYS_RECVMSG */ 113
558};
559
Roland McGratha4d48532005-06-08 20:45:28 +0000560#if defined (SPARC) || defined (SPARC64)
561static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000562sparc_socket_decode (tcp)
563struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564{
565 volatile long addr;
566 volatile int i, n;
567
568 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
569 return;
570 }
571 tcp->scno = socket_map [tcp->u_arg [0]-1];
572 n = tcp->u_nargs = sysent [tcp->scno].nargs;
573 addr = tcp->u_arg [1];
574 for (i = 0; i < n; i++){
575 int arg;
576 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
577 arg = 0;
578 tcp->u_arg [i] = arg;
579 addr += sizeof (arg);
580 }
581}
Roland McGratha4d48532005-06-08 20:45:28 +0000582#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
Roland McGratha4d48532005-06-08 20:45:28 +0000584static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585decode_subcall(tcp, subcall, nsubcalls, style)
586struct tcb *tcp;
587int subcall;
588int nsubcalls;
589enum subcall_style style;
590{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000591 long addr, mask, arg;
592 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000593
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 switch (style) {
595 case shift_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 if (sysent[tcp->scno].nargs != -1)
600 tcp->u_nargs = sysent[tcp->scno].nargs;
601 else
602 tcp->u_nargs--;
603 for (i = 0; i < tcp->u_nargs; i++)
604 tcp->u_arg[i] = tcp->u_arg[i + 1];
605 break;
606 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000607 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
608 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609 tcp->scno = subcall + tcp->u_arg[0];
610 addr = tcp->u_arg[1];
611 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
612 if (umove(tcp, addr, &arg) < 0)
613 arg = 0;
614 tcp->u_arg[i] = arg;
615 addr += sizeof(arg);
616 }
617 tcp->u_nargs = sysent[tcp->scno].nargs;
618 break;
619 case mask_style:
620 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 for (i = 0; mask; i++)
622 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000623 if (i >= nsubcalls)
624 return;
625 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626 tcp->scno = subcall + i;
627 if (sysent[tcp->scno].nargs != -1)
628 tcp->u_nargs = sysent[tcp->scno].nargs;
629 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000630 case door_style:
631 /*
632 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000633 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000634 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000635 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
636 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000637 tcp->scno = subcall + tcp->u_arg[5];
638 if (sysent[tcp->scno].nargs != -1)
639 tcp->u_nargs = sysent[tcp->scno].nargs;
640 else
641 tcp->u_nargs--;
642 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000643#ifdef FREEBSD
644 case table_style:
645 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
646 if (subcalls_table[i].call == tcp->scno) break;
647 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
648 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
649 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
650 for (i = 0; i < tcp->u_nargs; i++)
651 tcp->u_arg[i] = tcp->u_arg[i + 1];
652 }
653 break;
654#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000655 }
656}
657#endif
658
659struct tcb *tcp_last = NULL;
660
661static int
662internal_syscall(tcp)
663struct tcb *tcp;
664{
665 /*
666 * We must always trace a few critical system calls in order to
667 * correctly support following forks in the presence of tracing
668 * qualifiers.
669 */
Roland McGrath17352792005-06-07 23:21:26 +0000670 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671#ifdef SYS_fork
672 case SYS_fork:
673#endif
674#ifdef SYS_vfork
675 case SYS_vfork:
676#endif
John Hughes4e36a812001-04-18 15:11:51 +0000677#ifdef SYS_fork1
678 case SYS_fork1:
679#endif
680#ifdef SYS_forkall
681 case SYS_forkall:
682#endif
683#ifdef SYS_rfork1
684 case SYS_rfork1:
685#endif
686#ifdef SYS_rforkall
687 case SYS_rforkall:
688#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000689#ifdef SYS_rfork
690 case SYS_rfork:
691#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692 internal_fork(tcp);
693 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000694#ifdef SYS_clone
695 case SYS_clone:
696 internal_clone(tcp);
697 break;
698#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000699#ifdef SYS_clone2
700 case SYS_clone2:
701 internal_clone(tcp);
702 break;
703#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000704#ifdef SYS_execv
705 case SYS_execv:
706#endif
707#ifdef SYS_execve
708 case SYS_execve:
709#endif
John Hughes4e36a812001-04-18 15:11:51 +0000710#ifdef SYS_rexecve
711 case SYS_rexecve:
712#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000713 internal_exec(tcp);
714 break;
715
716#ifdef SYS_wait
717 case SYS_wait:
718#endif
719#ifdef SYS_wait4
720 case SYS_wait4:
721#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000722#ifdef SYS32_wait4
723 case SYS32_wait4:
724#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725#ifdef SYS_waitpid
726 case SYS_waitpid:
727#endif
728#ifdef SYS_waitsys
729 case SYS_waitsys:
730#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000731 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000733#ifdef SYS_waitid
734 case SYS_waitid:
735 internal_wait(tcp, 3);
736 break;
737#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000738
739#ifdef SYS_exit
740 case SYS_exit:
741#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000742#ifdef SYS32_exit
743 case SYS32_exit:
744#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000745#ifdef __NR_exit_group
746 case __NR_exit_group:
747#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000748#ifdef IA64
749 case 252: /* IA-32 __NR_exit_group */
750#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000751 internal_exit(tcp);
752 break;
753 }
754 return 0;
755}
756
Wichert Akkermanc7926982000-04-10 22:22:31 +0000757
758#ifdef LINUX
759#if defined (I386)
760 static long eax;
761#elif defined (IA64)
762 long r8, r10, psr;
763 long ia32 = 0;
764#elif defined (POWERPC)
765 static long result,flags;
766#elif defined (M68K)
767 static int d0;
768#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000769 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000770#elif defined (ALPHA)
771 static long r0;
772 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000773#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000774 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000775 static unsigned long trap;
776#elif defined(MIPS)
777 static long a3;
778 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000779#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000780 static long gpr2;
781 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000782 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000783#elif defined(HPPA)
784 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000785#elif defined(SH)
786 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000787#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000788 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000789#elif defined(X86_64)
790 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000791#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000792#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000793#ifdef FREEBSD
794 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000795#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000796
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000798get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799struct tcb *tcp;
800{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000802#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000804#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000807#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000808 if (tcp->flags & TCB_WAITEXECVE) {
809 /*
810 * When the execve system call completes successfully, the
811 * new process still has -ENOSYS (old style) or __NR_execve
812 * (new style) in gpr2. We cannot recover the scno again
813 * by disassembly, because the image that executed the
814 * syscall is gone now. Fortunately, we don't want it. We
815 * leave the flag set so that syscall_fixup can fake the
816 * result.
817 */
818 if (tcp->flags & TCB_INSYSCALL)
819 return 1;
820 /*
821 * This is the SIGTRAP after execve. We cannot try to read
822 * the system call here either.
823 */
824 tcp->flags &= ~TCB_WAITEXECVE;
825 return 0;
826 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000827
828 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
829 return -1;
830
831 if (syscall_mode != -ENOSYS) {
832 /*
833 * Since kernel version 2.5.44 the scno gets passed in gpr2.
834 */
835 scno = syscall_mode;
836 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000837 /*
838 * Old style of "passing" the scno via the SVC instruction.
839 */
840
841 long opcode, offset_reg, tmp;
842 void * svc_addr;
843 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
844 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
845 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
846 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000847
Michal Ludvig882eda82002-11-11 12:50:47 +0000848 if (upeek(pid, PT_PSWADDR, &pc) < 0)
849 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000850 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000852 if (errno) {
853 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000854 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000855 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000856
857 /*
858 * We have to check if the SVC got executed directly or via an
859 * EXECUTE instruction. In case of EXECUTE it is necessary to do
860 * instruction decoding to derive the system call number.
861 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
862 * so that this doesn't work if a SVC opcode is part of an EXECUTE
863 * opcode. Since there is no way to find out the opcode size this
864 * is the best we can do...
865 */
866
867 if ((opcode & 0xff00) == 0x0a00) {
868 /* SVC opcode */
869 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000870 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000871 else {
872 /* SVC got executed by EXECUTE instruction */
873
874 /*
875 * Do instruction decoding of EXECUTE. If you really want to
876 * understand this, read the Principles of Operations.
877 */
878 svc_addr = (void *) (opcode & 0xfff);
879
880 tmp = 0;
881 offset_reg = (opcode & 0x000f0000) >> 16;
882 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
883 return -1;
884 svc_addr += tmp;
885
886 tmp = 0;
887 offset_reg = (opcode & 0x0000f000) >> 12;
888 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
889 return -1;
890 svc_addr += tmp;
891
892 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
893 if (errno)
894 return -1;
895#if defined(S390X)
896 scno >>= 48;
897#else
898 scno >>= 16;
899#endif
900 tmp = 0;
901 offset_reg = (opcode & 0x00f00000) >> 20;
902 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
903 return -1;
904
905 scno = (scno | tmp) & 0xff;
906 }
907 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000908#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000909 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910 return -1;
911 if (!(tcp->flags & TCB_INSYSCALL)) {
912 /* Check if we return from execve. */
913 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
914 tcp->flags &= ~TCB_WAITEXECVE;
915 return 0;
916 }
917 }
918#elif defined (I386)
919 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
920 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000921#elif defined (X86_64)
922 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
923 return -1;
924
Roland McGrath761b5d72002-12-15 23:58:31 +0000925 if (!(tcp->flags & TCB_INSYSCALL)) {
926 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 long val;
928
929 /* Check CS register value. On x86-64 linux it is:
930 * 0x33 for long mode (64 bit)
931 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000932 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000933 * to be cached.
934 */
935 if (upeek(pid, 8*CS, &val) < 0)
936 return -1;
937 switch(val)
938 {
939 case 0x23: currpers = 1; break;
940 case 0x33: currpers = 0; break;
941 default:
942 fprintf(stderr, "Unknown value CS=0x%02X while "
943 "detecting personality of process "
944 "PID=%d\n", (int)val, pid);
945 currpers = current_personality;
946 break;
947 }
948#if 0
949 /* This version analyzes the opcode of a syscall instruction.
950 * (int 0x80 on i386 vs. syscall on x86-64)
951 * It works, but is too complicated.
952 */
953 unsigned long val, rip, i;
954
955 if(upeek(pid, 8*RIP, &rip)<0)
956 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000957
Michal Ludvig0e035502002-09-23 15:41:01 +0000958 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
959 rip-=2;
960 errno = 0;
961
Roland McGrath761b5d72002-12-15 23:58:31 +0000962 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
963 if (errno)
964 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000965 strerror(errno));
966 switch (call & 0xffff)
967 {
968 /* x86-64: syscall = 0x0f 0x05 */
969 case 0x050f: currpers = 0; break;
970 /* i386: int 0x80 = 0xcd 0x80 */
971 case 0x80cd: currpers = 1; break;
972 default:
973 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000974 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000975 "Unknown syscall opcode (0x%04X) while "
976 "detecting personality of process "
977 "PID=%d\n", (int)call, pid);
978 break;
979 }
980#endif
981 if(currpers != current_personality)
982 {
983 char *names[]={"64 bit", "32 bit"};
984 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000985 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000986 pid, names[current_personality]);
987 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000988 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000989#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000990# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000991 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000992 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000993 if (!(tcp->flags & TCB_INSYSCALL)) {
994 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000995 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000996 return -1;
997 } else {
998 if (upeek (pid, PT_R15, &scno) < 0)
999 return -1;
1000 }
Roland McGrathba954762003-03-05 06:29:06 +00001001 /* Check if we return from execve. */
1002 if (tcp->flags & TCB_WAITEXECVE) {
1003 tcp->flags &= ~TCB_WAITEXECVE;
1004 return 0;
1005 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001006 } else {
1007 /* syscall in progress */
1008 if (upeek (pid, PT_R8, &r8) < 0)
1009 return -1;
1010 if (upeek (pid, PT_R10, &r10) < 0)
1011 return -1;
1012 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 /*
1015 * Read complete register set in one go.
1016 */
1017 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1018 return -1;
1019
1020 /*
1021 * We only need to grab the syscall number on syscall entry.
1022 */
1023 if (regs.ARM_ip == 0) {
1024 /*
1025 * Note: we only deal with only 32-bit CPUs here.
1026 */
1027 if (regs.ARM_cpsr & 0x20) {
1028 /*
1029 * Get the Thumb-mode system call number
1030 */
1031 scno = regs.ARM_r7;
1032 } else {
1033 /*
1034 * Get the ARM-mode system call number
1035 */
1036 errno = 0;
1037 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1038 if (errno)
1039 return -1;
1040
1041 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1042 tcp->flags &= ~TCB_WAITEXECVE;
1043 return 0;
1044 }
1045
1046 if ((scno & 0x0ff00000) != 0x0f900000) {
1047 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1048 scno);
1049 return -1;
1050 }
1051
1052 /*
1053 * Fixup the syscall number
1054 */
1055 scno &= 0x000fffff;
1056 }
1057
1058 if (tcp->flags & TCB_INSYSCALL) {
1059 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1060 tcp->flags &= ~TCB_INSYSCALL;
1061 }
1062 } else {
1063 if (!(tcp->flags & TCB_INSYSCALL)) {
1064 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1065 tcp->flags |= TCB_INSYSCALL;
1066 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 }
1068#elif defined (M68K)
1069 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1070 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001071#elif defined (MIPS)
1072 if (upeek(pid, REG_A3, &a3) < 0)
1073 return -1;
1074
1075 if(!(tcp->flags & TCB_INSYSCALL)) {
1076 if (upeek(pid, REG_V0, &scno) < 0)
1077 return -1;
1078
1079 if (scno < 0 || scno > nsyscalls) {
1080 if(a3 == 0 || a3 == -1) {
1081 if(debug)
1082 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1083 return 0;
1084 }
1085 }
1086 } else {
1087 if (upeek(pid, REG_V0, &r2) < 0)
1088 return -1;
1089 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090#elif defined (ALPHA)
1091 if (upeek(pid, REG_A3, &a3) < 0)
1092 return -1;
1093
1094 if (!(tcp->flags & TCB_INSYSCALL)) {
1095 if (upeek(pid, REG_R0, &scno) < 0)
1096 return -1;
1097
1098 /* Check if we return from execve. */
1099 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1100 tcp->flags &= ~TCB_WAITEXECVE;
1101 return 0;
1102 }
1103
1104 /*
1105 * Do some sanity checks to figure out if it's
1106 * really a syscall entry
1107 */
1108 if (scno < 0 || scno > nsyscalls) {
1109 if (a3 == 0 || a3 == -1) {
1110 if (debug)
1111 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1112 return 0;
1113 }
1114 }
1115 }
1116 else {
1117 if (upeek(pid, REG_R0, &r0) < 0)
1118 return -1;
1119 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001120#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121 /* Everything we need is in the current register set. */
1122 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1123 return -1;
1124
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 /* If we are entering, then disassemble the syscall trap. */
1126 if (!(tcp->flags & TCB_INSYSCALL)) {
1127 /* Retrieve the syscall trap instruction. */
1128 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001129 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001130#if defined(SPARC64)
1131 trap >>= 32;
1132#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 if (errno)
1134 return -1;
1135
1136 /* Disassemble the trap to see what personality to use. */
1137 switch (trap) {
1138 case 0x91d02010:
1139 /* Linux/SPARC syscall trap. */
1140 set_personality(0);
1141 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001142 case 0x91d0206d:
1143 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001144 set_personality(2);
1145 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 case 0x91d02000:
1147 /* SunOS syscall trap. (pers 1) */
1148 fprintf(stderr,"syscall: SunOS no support\n");
1149 return -1;
1150 case 0x91d02008:
1151 /* Solaris 2.x syscall trap. (per 2) */
1152 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001153 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 case 0x91d02009:
1155 /* NetBSD/FreeBSD syscall trap. */
1156 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1157 return -1;
1158 case 0x91d02027:
1159 /* Solaris 2.x gettimeofday */
1160 set_personality(1);
1161 break;
1162 default:
1163 /* Unknown syscall trap. */
1164 if(tcp->flags & TCB_WAITEXECVE) {
1165 tcp->flags &= ~TCB_WAITEXECVE;
1166 return 0;
1167 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001168#if defined (SPARC64)
1169 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1170#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001171 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001172#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 return -1;
1174 }
1175
1176 /* Extract the system call number from the registers. */
1177 if (trap == 0x91d02027)
1178 scno = 156;
1179 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001180 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001182 scno = regs.r_o0;
1183 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 }
1185 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001186#elif defined(HPPA)
1187 if (upeek(pid, PT_GR20, &scno) < 0)
1188 return -1;
1189 if (!(tcp->flags & TCB_INSYSCALL)) {
1190 /* Check if we return from execve. */
1191 if ((tcp->flags & TCB_WAITEXECVE)) {
1192 tcp->flags &= ~TCB_WAITEXECVE;
1193 return 0;
1194 }
1195 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001196#elif defined(SH)
1197 /*
1198 * In the new syscall ABI, the system call number is in R3.
1199 */
1200 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1201 return -1;
1202
1203 if (scno < 0) {
1204 /* Odd as it may seem, a glibc bug has been known to cause
1205 glibc to issue bogus negative syscall numbers. So for
1206 our purposes, make strace print what it *should* have been */
1207 long correct_scno = (scno & 0xff);
1208 if (debug)
1209 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001210 "Detected glibc bug: bogus system call number = %ld, "
1211 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001212 scno,
1213 correct_scno);
1214 scno = correct_scno;
1215 }
1216
1217
1218 if (!(tcp->flags & TCB_INSYSCALL)) {
1219 /* Check if we return from execve. */
1220 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1221 tcp->flags &= ~TCB_WAITEXECVE;
1222 return 0;
1223 }
1224 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001225#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001226 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1227 return -1;
1228 scno &= 0xFFFF;
1229
1230 if (!(tcp->flags & TCB_INSYSCALL)) {
1231 /* Check if we return from execve. */
1232 if (tcp->flags & TCB_WAITEXECVE) {
1233 tcp->flags &= ~TCB_WAITEXECVE;
1234 return 0;
1235 }
1236 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001237#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238#endif /* LINUX */
1239#ifdef SUNOS4
1240 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1241 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001242#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001243 /* new syscall ABI returns result in R0 */
1244 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1245 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001246#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001247 /* ABI defines result returned in r9 */
1248 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1249 return -1;
1250
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001252#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001254 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001256#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001257 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001258#else /* FREEBSD */
1259 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1260 perror("pread");
1261 return -1;
1262 }
1263 switch (regs.r_eax) {
1264 case SYS_syscall:
1265 case SYS___syscall:
1266 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1267 break;
1268 default:
1269 scno = regs.r_eax;
1270 break;
1271 }
1272#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001274#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001275 if (!(tcp->flags & TCB_INSYSCALL))
1276 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001277 return 1;
1278}
1279
Pavel Machek4dc3b142000-02-01 17:58:41 +00001280
Roland McGrath17352792005-06-07 23:21:26 +00001281long
1282known_scno(tcp)
1283struct tcb *tcp;
1284{
1285 long scno = tcp->scno;
1286 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1287 scno = sysent[scno].native_scno;
1288 else
1289 scno += NR_SYSCALL_BASE;
1290 return scno;
1291}
1292
Roland McGratha4d48532005-06-08 20:45:28 +00001293static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001294syscall_fixup(tcp)
1295struct tcb *tcp;
1296{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001298 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001299#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001300 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001301
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001303 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304 if (
1305 scno == SYS_fork
1306#ifdef SYS_vfork
1307 || scno == SYS_vfork
1308#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001309#ifdef SYS_fork1
1310 || scno == SYS_fork1
1311#endif /* SYS_fork1 */
1312#ifdef SYS_forkall
1313 || scno == SYS_forkall
1314#endif /* SYS_forkall */
1315#ifdef SYS_rfork1
1316 || scno == SYS_rfork1
1317#endif /* SYS_fork1 */
1318#ifdef SYS_rforkall
1319 || scno == SYS_rforkall
1320#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321 ) {
1322 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001323 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001325 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326 }
1327 else {
1328 fprintf(stderr, "syscall: missing entry\n");
1329 tcp->flags |= TCB_INSYSCALL;
1330 }
1331 }
1332 }
1333 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 fprintf(stderr, "syscall: missing exit\n");
1336 tcp->flags &= ~TCB_INSYSCALL;
1337 }
1338 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001340#ifdef SUNOS4
1341 if (!(tcp->flags & TCB_INSYSCALL)) {
1342 if (scno == 0) {
1343 fprintf(stderr, "syscall: missing entry\n");
1344 tcp->flags |= TCB_INSYSCALL;
1345 }
1346 }
1347 else {
1348 if (scno != 0) {
1349 if (debug) {
1350 /*
1351 * This happens when a signal handler
1352 * for a signal which interrupted a
1353 * a system call makes another system call.
1354 */
1355 fprintf(stderr, "syscall: missing exit\n");
1356 }
1357 tcp->flags &= ~TCB_INSYSCALL;
1358 }
1359 }
1360#endif /* SUNOS4 */
1361#ifdef LINUX
1362#if defined (I386)
1363 if (upeek(pid, 4*EAX, &eax) < 0)
1364 return -1;
1365 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1366 if (debug)
1367 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1368 return 0;
1369 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001370#elif defined (X86_64)
1371 if (upeek(pid, 8*RAX, &rax) < 0)
1372 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001373 if (current_personality == 1)
1374 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001375 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1376 if (debug)
1377 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1378 return 0;
1379 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001380#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001381 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1382 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001383 if (syscall_mode != -ENOSYS)
1384 syscall_mode = tcp->scno;
1385 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001386 if (debug)
1387 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1388 return 0;
1389 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001390 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1391 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1392 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1393 /*
1394 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1395 * flag set for the post-execve SIGTRAP to see and reset.
1396 */
1397 gpr2 = 0;
1398 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399#elif defined (POWERPC)
1400# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001401 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001403 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001404 return -1;
1405 if (flags & SO_MASK)
1406 result = -result;
1407#elif defined (M68K)
1408 if (upeek(pid, 4*PT_D0, &d0) < 0)
1409 return -1;
1410 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1411 if (debug)
1412 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1413 return 0;
1414 }
1415#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001416 /*
1417 * Nothing required
1418 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001419#elif defined (HPPA)
1420 if (upeek(pid, PT_GR28, &r28) < 0)
1421 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001422#elif defined(IA64)
1423 if (upeek(pid, PT_R10, &r10) < 0)
1424 return -1;
1425 if (upeek(pid, PT_R8, &r8) < 0)
1426 return -1;
1427 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1428 if (debug)
1429 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1430 return 0;
1431 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432#endif
1433#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001434 return 1;
1435}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436
Roland McGratha4d48532005-06-08 20:45:28 +00001437static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001438get_error(tcp)
1439struct tcb *tcp;
1440{
1441 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001442#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001443#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001444 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1445 tcp->u_rval = -1;
1446 u_error = -gpr2;
1447 }
1448 else {
1449 tcp->u_rval = gpr2;
1450 u_error = 0;
1451 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001452#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001453#ifdef I386
1454 if (eax < 0 && -eax < nerrnos) {
1455 tcp->u_rval = -1;
1456 u_error = -eax;
1457 }
1458 else {
1459 tcp->u_rval = eax;
1460 u_error = 0;
1461 }
1462#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001463#ifdef X86_64
1464 if (rax < 0 && -rax < nerrnos) {
1465 tcp->u_rval = -1;
1466 u_error = -rax;
1467 }
1468 else {
1469 tcp->u_rval = rax;
1470 u_error = 0;
1471 }
1472#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001473#ifdef IA64
1474 if (ia32) {
1475 int err;
1476
1477 err = (int)r8;
1478 if (err < 0 && -err < nerrnos) {
1479 tcp->u_rval = -1;
1480 u_error = -err;
1481 }
1482 else {
1483 tcp->u_rval = err;
1484 u_error = 0;
1485 }
1486 } else {
1487 if (r10) {
1488 tcp->u_rval = -1;
1489 u_error = r8;
1490 } else {
1491 tcp->u_rval = r8;
1492 u_error = 0;
1493 }
1494 }
1495#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001496#ifdef MIPS
1497 if (a3) {
1498 tcp->u_rval = -1;
1499 u_error = r2;
1500 } else {
1501 tcp->u_rval = r2;
1502 u_error = 0;
1503 }
1504#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001506 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507 tcp->u_rval = -1;
1508 u_error = -result;
1509 }
1510 else {
1511 tcp->u_rval = result;
1512 u_error = 0;
1513 }
1514#else /* !POWERPC */
1515#ifdef M68K
1516 if (d0 && (unsigned) -d0 < nerrnos) {
1517 tcp->u_rval = -1;
1518 u_error = -d0;
1519 }
1520 else {
1521 tcp->u_rval = d0;
1522 u_error = 0;
1523 }
1524#else /* !M68K */
1525#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001526 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001528 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529 }
1530 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001531 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001532 u_error = 0;
1533 }
1534#else /* !ARM */
1535#ifdef ALPHA
1536 if (a3) {
1537 tcp->u_rval = -1;
1538 u_error = r0;
1539 }
1540 else {
1541 tcp->u_rval = r0;
1542 u_error = 0;
1543 }
1544#else /* !ALPHA */
1545#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001546 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001548 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549 }
1550 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001551 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552 u_error = 0;
1553 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001554#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001555#ifdef SPARC64
1556 if (regs.r_tstate & 0x1100000000UL) {
1557 tcp->u_rval = -1;
1558 u_error = regs.r_o0;
1559 }
1560 else {
1561 tcp->u_rval = regs.r_o0;
1562 u_error = 0;
1563 }
1564#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001565#ifdef HPPA
1566 if (r28 && (unsigned) -r28 < nerrnos) {
1567 tcp->u_rval = -1;
1568 u_error = -r28;
1569 }
1570 else {
1571 tcp->u_rval = r28;
1572 u_error = 0;
1573 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001574#else
1575#ifdef SH
1576 /* interpret R0 as return value or error number */
1577 if (r0 && (unsigned) -r0 < nerrnos) {
1578 tcp->u_rval = -1;
1579 u_error = -r0;
1580 }
1581 else {
1582 tcp->u_rval = r0;
1583 u_error = 0;
1584 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001585#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001586#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001587 /* interpret result as return value or error number */
1588 if (r9 && (unsigned) -r9 < nerrnos) {
1589 tcp->u_rval = -1;
1590 u_error = -r9;
1591 }
1592 else {
1593 tcp->u_rval = r9;
1594 u_error = 0;
1595 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001596#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001597#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001598#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001600#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601#endif /* ALPHA */
1602#endif /* ARM */
1603#endif /* M68K */
1604#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001605#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001606#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001607#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001609#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001610#endif /* LINUX */
1611#ifdef SUNOS4
1612 /* get error code from user struct */
1613 if (upeek(pid, uoff(u_error), &u_error) < 0)
1614 return -1;
1615 u_error >>= 24; /* u_error is a char */
1616
1617 /* get system call return value */
1618 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1619 return -1;
1620#endif /* SUNOS4 */
1621#ifdef SVR4
1622#ifdef SPARC
1623 /* Judicious guessing goes a long way. */
1624 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1625 tcp->u_rval = -1;
1626 u_error = tcp->status.pr_reg[R_O0];
1627 }
1628 else {
1629 tcp->u_rval = tcp->status.pr_reg[R_O0];
1630 u_error = 0;
1631 }
1632#endif /* SPARC */
1633#ifdef I386
1634 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001635 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001637 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638 }
1639 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001640 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001641#ifdef HAVE_LONG_LONG
1642 tcp->u_lrval =
1643 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1644 tcp->status.PR_REG[EAX];
1645#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 u_error = 0;
1647 }
1648#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001649#ifdef X86_64
1650 /* Wanna know how to kill an hour single-stepping? */
1651 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1652 tcp->u_rval = -1;
1653 u_error = tcp->status.PR_REG[RAX];
1654 }
1655 else {
1656 tcp->u_rval = tcp->status.PR_REG[RAX];
1657 u_error = 0;
1658 }
1659#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660#ifdef MIPS
1661 if (tcp->status.pr_reg[CTX_A3]) {
1662 tcp->u_rval = -1;
1663 u_error = tcp->status.pr_reg[CTX_V0];
1664 }
1665 else {
1666 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1667 u_error = 0;
1668 }
1669#endif /* MIPS */
1670#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001671#ifdef FREEBSD
1672 if (regs.r_eflags & PSL_C) {
1673 tcp->u_rval = -1;
1674 u_error = regs.r_eax;
1675 } else {
1676 tcp->u_rval = regs.r_eax;
1677 tcp->u_lrval =
1678 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1679 u_error = 0;
1680 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001681#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001682 tcp->u_error = u_error;
1683 return 1;
1684}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685
Roland McGrathb69f81b2002-12-21 23:25:18 +00001686int
1687force_result(tcp, error, rval)
1688 struct tcb *tcp;
1689 int error;
1690 long rval;
1691{
1692#ifdef LINUX
1693#if defined(S390) || defined(S390X)
1694 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001695 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1696 return -1;
1697#else /* !S390 && !S390X */
1698#ifdef I386
1699 eax = error ? -error : rval;
1700 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1701 return -1;
1702#else /* !I386 */
1703#ifdef X86_64
1704 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001705 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001706 return -1;
1707#else
1708#ifdef IA64
1709 if (ia32) {
1710 r8 = error ? -error : rval;
1711 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1712 return -1;
1713 }
1714 else {
1715 if (error) {
1716 r8 = error;
1717 r10 = -1;
1718 }
1719 else {
1720 r8 = rval;
1721 r10 = 0;
1722 }
1723 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1724 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1725 return -1;
1726 }
1727#else /* !IA64 */
1728#ifdef MIPS
1729 if (error) {
1730 r2 = error;
1731 a3 = -1;
1732 }
1733 else {
1734 r2 = rval;
1735 a3 = 0;
1736 }
1737 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1738 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1739 return -1;
1740#else
1741#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001742 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001743 return -1;
1744 if (error) {
1745 flags |= SO_MASK;
1746 result = error;
1747 }
1748 else {
1749 flags &= ~SO_MASK;
1750 result = rval;
1751 }
Roland McGratheb285352003-01-14 09:59:00 +00001752 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1753 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001754 return -1;
1755#else /* !POWERPC */
1756#ifdef M68K
1757 d0 = error ? -error : rval;
1758 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1759 return -1;
1760#else /* !M68K */
1761#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001762 regs.ARM_r0 = error ? -error : rval;
1763 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001764 return -1;
1765#else /* !ARM */
1766#ifdef ALPHA
1767 if (error) {
1768 a3 = -1;
1769 r0 = error;
1770 }
1771 else {
1772 a3 = 0;
1773 r0 = rval;
1774 }
1775 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1776 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1777 return -1;
1778#else /* !ALPHA */
1779#ifdef SPARC
1780 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1781 return -1;
1782 if (error) {
1783 regs.r_psr |= PSR_C;
1784 regs.r_o0 = error;
1785 }
1786 else {
1787 regs.r_psr &= ~PSR_C;
1788 regs.r_o0 = rval;
1789 }
1790 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1791 return -1;
1792#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001793#ifdef SPARC64
1794 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1795 return -1;
1796 if (error) {
1797 regs.r_tstate |= 0x1100000000UL;
1798 regs.r_o0 = error;
1799 }
1800 else {
1801 regs.r_tstate &= ~0x1100000000UL;
1802 regs.r_o0 = rval;
1803 }
1804 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1805 return -1;
1806#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001807#ifdef HPPA
1808 r28 = error ? -error : rval;
1809 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1810 return -1;
1811#else
1812#ifdef SH
1813 r0 = error ? -error : rval;
1814 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1815 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001816#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001817#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001818 r9 = error ? -error : rval;
1819 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1820 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001821#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822#endif /* SH */
1823#endif /* HPPA */
1824#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001825#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001826#endif /* ALPHA */
1827#endif /* ARM */
1828#endif /* M68K */
1829#endif /* POWERPC */
1830#endif /* MIPS */
1831#endif /* IA64 */
1832#endif /* X86_64 */
1833#endif /* I386 */
1834#endif /* S390 || S390X */
1835#endif /* LINUX */
1836#ifdef SUNOS4
1837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1838 error << 24) < 0 ||
1839 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1840 return -1;
1841#endif /* SUNOS4 */
1842#ifdef SVR4
1843 /* XXX no clue */
1844 return -1;
1845#endif /* SVR4 */
1846#ifdef FREEBSD
1847 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1848 perror("pread");
1849 return -1;
1850 }
1851 if (error) {
1852 regs.r_eflags |= PSL_C;
1853 regs.r_eax = error;
1854 }
1855 else {
1856 regs.r_eflags &= ~PSL_C;
1857 regs.r_eax = rval;
1858 }
1859 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1860 perror("pwrite");
1861 return -1;
1862 }
1863#endif /* FREEBSD */
1864
1865 /* All branches reach here on success (only). */
1866 tcp->u_error = error;
1867 tcp->u_rval = rval;
1868 return 0;
1869}
1870
Roland McGratha4d48532005-06-08 20:45:28 +00001871static int
1872syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001873struct tcb *tcp;
1874{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001875#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001876 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001877#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001879#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001880 {
1881 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001882 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1883 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001884 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001885 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001886 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001887 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001888 return -1;
1889 }
1890 }
1891#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001892 {
1893 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001894 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1895 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001896 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001897 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001899 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1900 * for scno somewhere above here!
1901 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001902 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1903 return -1;
1904 }
1905 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001906#elif defined (IA64)
1907 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001908 if (!ia32) {
1909 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1910 /* be backwards compatible with kernel < 2.4.4... */
1911# ifndef PT_RBS_END
1912# define PT_RBS_END PT_AR_BSP
1913# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001914
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001915 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001916 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001917 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1918 return -1;
1919
1920 sof = (cfm >> 0) & 0x7f;
1921 sol = (cfm >> 7) & 0x7f;
1922 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1923
1924 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1925 && sysent[tcp->scno].nargs != -1)
1926 tcp->u_nargs = sysent[tcp->scno].nargs;
1927 else
1928 tcp->u_nargs = MAX_ARGS;
1929 for (i = 0; i < tcp->u_nargs; ++i) {
1930 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1931 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1932 return -1;
1933 }
1934 } else {
1935 int i;
1936
1937 if (/* EBX = out0 */
1938 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1939 /* ECX = out1 */
1940 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1941 /* EDX = out2 */
1942 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1943 /* ESI = out3 */
1944 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1945 /* EDI = out4 */
1946 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1947 /* EBP = out5 */
1948 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1949 return -1;
1950
1951 for (i = 0; i < 6; ++i)
1952 /* truncate away IVE sign-extension */
1953 tcp->u_arg[i] &= 0xffffffff;
1954
1955 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1956 && sysent[tcp->scno].nargs != -1)
1957 tcp->u_nargs = sysent[tcp->scno].nargs;
1958 else
1959 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001960 }
1961 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001962#elif defined (MIPS)
1963 {
1964 long sp;
1965 int i, nargs;
1966
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001967 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1968 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001969 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001970 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001971 if(nargs > 4) {
1972 if(upeek(pid, REG_SP, &sp) < 0)
1973 return -1;
1974 for(i = 0; i < 4; i++) {
1975 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1976 return -1;
1977 }
1978 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1979 (char *)(tcp->u_arg + 4));
1980 } else {
1981 for(i = 0; i < nargs; i++) {
1982 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1983 return -1;
1984 }
1985 }
1986 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001987#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00001988#ifndef PT_ORIG_R3
1989#define PT_ORIG_R3 34
1990#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001991 {
1992 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001993 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1994 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001995 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001996 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001997 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00001998 if (upeek(pid, (i==0) ?
1999 (sizeof(unsigned long)*PT_ORIG_R3) :
2000 ((i+PT_R3)*sizeof(unsigned long)),
2001 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002 return -1;
2003 }
2004 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002005#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002007 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002008
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 Akkermanbf79f2e2000-09-01 21:03:06 +00002012 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002013 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002014 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002015 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002016#elif defined (HPPA)
2017 {
2018 int i;
2019
2020 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2021 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002022 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002023 tcp->u_nargs = MAX_ARGS;
2024 for (i = 0; i < tcp->u_nargs; i++) {
2025 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2026 return -1;
2027 }
2028 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002029#elif defined(ARM)
2030 {
2031 int i;
2032
2033 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2034 tcp->u_nargs = sysent[tcp->scno].nargs;
2035 else
2036 tcp->u_nargs = MAX_ARGS;
2037 for (i = 0; i < tcp->u_nargs; i++)
2038 tcp->u_arg[i] = regs.uregs[i];
2039 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002040#elif defined(SH)
2041 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002042 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002043 static int syscall_regs[] = {
2044 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2045 REG_REG0, REG_REG0+1, REG_REG0+2
2046 };
2047
2048 tcp->u_nargs = sysent[tcp->scno].nargs;
2049 for (i = 0; i < tcp->u_nargs; i++) {
2050 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2051 return -1;
2052 }
2053 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002054#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002055 {
2056 int i;
2057 /* Registers used by SH5 Linux system calls for parameters */
2058 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2059
2060 /*
2061 * TODO: should also check that the number of arguments encoded
2062 * in the trap number matches the number strace expects.
2063 */
2064 /*
2065 assert(sysent[tcp->scno].nargs <
2066 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2067 */
2068
2069 tcp->u_nargs = sysent[tcp->scno].nargs;
2070 for (i = 0; i < tcp->u_nargs; i++) {
2071 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2072 return -1;
2073 }
2074 }
2075
Michal Ludvig0e035502002-09-23 15:41:01 +00002076#elif defined(X86_64)
2077 {
2078 int i;
2079 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2080 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002081 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002082 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002083
Michal Ludvig0e035502002-09-23 15:41:01 +00002084 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2085 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002086 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002087 tcp->u_nargs = MAX_ARGS;
2088 for (i = 0; i < tcp->u_nargs; i++) {
2089 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2090 return -1;
2091 }
2092 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002093#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002094 {
2095 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002096 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2097 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002098 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100 for (i = 0; i < tcp->u_nargs; i++) {
2101 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2102 return -1;
2103 }
2104 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002105#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002106#endif /* LINUX */
2107#ifdef SUNOS4
2108 {
2109 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002110 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2111 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002112 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002113 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 for (i = 0; i < tcp->u_nargs; i++) {
2115 struct user *u;
2116
2117 if (upeek(pid, uoff(u_arg[0]) +
2118 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2119 return -1;
2120 }
2121 }
2122#endif /* SUNOS4 */
2123#ifdef SVR4
2124#ifdef MIPS
2125 /*
2126 * SGI is broken: even though it has pr_sysarg, it doesn't
2127 * set them on system call entry. Get a clue.
2128 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002129 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130 tcp->u_nargs = sysent[tcp->scno].nargs;
2131 else
2132 tcp->u_nargs = tcp->status.pr_nsysarg;
2133 if (tcp->u_nargs > 4) {
2134 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2135 4*sizeof(tcp->u_arg[0]));
2136 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2137 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2138 }
2139 else {
2140 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2141 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2142 }
John Hughes25299712001-03-06 10:10:06 +00002143#elif UNIXWARE >= 2
2144 /*
2145 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2146 */
2147 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2148 tcp->u_nargs = sysent[tcp->scno].nargs;
2149 else
2150 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2151 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2152 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2153#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002154 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155 tcp->u_nargs = sysent[tcp->scno].nargs;
2156 else
2157 tcp->u_nargs = tcp->status.pr_nsysarg;
2158 {
2159 int i;
2160 for (i = 0; i < tcp->u_nargs; i++)
2161 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2162 }
John Hughes25299712001-03-06 10:10:06 +00002163#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002164 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165 tcp->u_nargs = sysent[tcp->scno].nargs;
2166 else
2167 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002168 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002170#else
2171 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002173#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002174#ifdef FREEBSD
2175 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2176 sysent[tcp->scno].nargs > tcp->status.val)
2177 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002178 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002179 tcp->u_nargs = tcp->status.val;
2180 if (tcp->u_nargs < 0)
2181 tcp->u_nargs = 0;
2182 if (tcp->u_nargs > MAX_ARGS)
2183 tcp->u_nargs = MAX_ARGS;
2184 switch(regs.r_eax) {
2185 case SYS___syscall:
2186 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2187 regs.r_esp + sizeof(int) + sizeof(quad_t));
2188 break;
2189 case SYS_syscall:
2190 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2191 regs.r_esp + 2 * sizeof(int));
2192 break;
2193 default:
2194 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2195 regs.r_esp + sizeof(int));
2196 break;
2197 }
2198#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002199 return 1;
2200}
2201
2202int
2203trace_syscall(tcp)
2204struct tcb *tcp;
2205{
2206 int sys_res;
2207 struct timeval tv;
2208 int res;
2209
2210 /* Measure the exit time as early as possible to avoid errors. */
2211 if (dtime && (tcp->flags & TCB_INSYSCALL))
2212 gettimeofday(&tv, NULL);
2213
2214 res = get_scno(tcp);
2215 if (res != 1)
2216 return res;
2217
2218 res = syscall_fixup(tcp);
2219 if (res != 1)
2220 return res;
2221
2222 if (tcp->flags & TCB_INSYSCALL) {
2223 long u_error;
2224 res = get_error(tcp);
2225 if (res != 1)
2226 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002227
2228 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002229 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2230 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002231 tcp->flags &= ~TCB_INSYSCALL;
2232 return 0;
2233 }
2234
2235 if (tcp->flags & TCB_REPRINT) {
2236 printleader(tcp);
2237 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002239 tprintf("syscall_%lu", tcp->scno);
2240 else
2241 tprintf("%s", sysent[tcp->scno].sys_name);
2242 tprintf(" resumed> ");
2243 }
2244
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002245 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002246 if (counts == NULL) {
2247 counts = calloc(sizeof *counts, nsyscalls);
2248 if (counts == NULL) {
2249 fprintf(stderr, "\
2250strace: out of memory for call counts\n");
2251 exit(1);
2252 }
2253 }
2254
2255 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002256 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002257 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002258 tv_sub(&tv, &tv, &tcp->etime);
2259#ifdef LINUX
2260 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002261 static struct timeval one_tick;
2262 if (one_tick.tv_usec == 0) {
2263 /* Initialize it. */
2264 struct itimerval it;
2265 memset(&it, 0, sizeof it);
2266 it.it_interval.tv_usec = 1;
2267 setitimer(ITIMER_REAL, &it, NULL);
2268 getitimer(ITIMER_REAL, &it);
2269 one_tick = it.it_interval;
2270 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002271
2272 if (tv_nz(&tcp->dtime))
2273 tv = tcp->dtime;
2274 else if (tv_cmp(&tv, &one_tick) > 0) {
2275 if (tv_cmp(&shortest, &one_tick) < 0)
2276 tv = shortest;
2277 else
2278 tv = one_tick;
2279 }
2280 }
2281#endif /* LINUX */
2282 if (tv_cmp(&tv, &shortest) < 0)
2283 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002284 tv_add(&counts[tcp->scno].time,
2285 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002286 tcp->flags &= ~TCB_INSYSCALL;
2287 return 0;
2288 }
2289
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002290 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002291 || (qual_flags[tcp->scno] & QUAL_RAW))
2292 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002293 else {
2294 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002295 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002296 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002297 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002298 u_error = tcp->u_error;
2299 tprintf(") ");
2300 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002301 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2302 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002303 if (u_error)
2304 tprintf("= -1 (errno %ld)", u_error);
2305 else
2306 tprintf("= %#lx", tcp->u_rval);
2307 }
2308 else if (!(sys_res & RVAL_NONE) && u_error) {
2309 switch (u_error) {
2310#ifdef LINUX
2311 case ERESTARTSYS:
2312 tprintf("= ? ERESTARTSYS (To be restarted)");
2313 break;
2314 case ERESTARTNOINTR:
2315 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2316 break;
2317 case ERESTARTNOHAND:
2318 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2319 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002320 case ERESTART_RESTARTBLOCK:
2321 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2322 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002323#endif /* LINUX */
2324 default:
2325 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002326 if (u_error < 0)
2327 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002328 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002329 tprintf("%s (%s)", errnoent[u_error],
2330 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002332 tprintf("ERRNO_%ld (%s)", u_error,
2333 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002334 break;
2335 }
2336 }
2337 else {
2338 if (sys_res & RVAL_NONE)
2339 tprintf("= ?");
2340 else {
2341 switch (sys_res & RVAL_MASK) {
2342 case RVAL_HEX:
2343 tprintf("= %#lx", tcp->u_rval);
2344 break;
2345 case RVAL_OCTAL:
2346 tprintf("= %#lo", tcp->u_rval);
2347 break;
2348 case RVAL_UDECIMAL:
2349 tprintf("= %lu", tcp->u_rval);
2350 break;
2351 case RVAL_DECIMAL:
2352 tprintf("= %ld", tcp->u_rval);
2353 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002354#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002355 case RVAL_LHEX:
2356 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002357 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358 case RVAL_LOCTAL:
2359 tprintf("= %#llo", tcp->u_lrval);
2360 break;
2361 case RVAL_LUDECIMAL:
2362 tprintf("= %llu", tcp->u_lrval);
2363 break;
2364 case RVAL_LDECIMAL:
2365 tprintf("= %lld", tcp->u_lrval);
2366 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002367#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002368 default:
2369 fprintf(stderr,
2370 "invalid rval format\n");
2371 break;
2372 }
2373 }
2374 if ((sys_res & RVAL_STR) && tcp->auxstr)
2375 tprintf(" (%s)", tcp->auxstr);
2376 }
2377 if (dtime) {
2378 tv_sub(&tv, &tv, &tcp->etime);
2379 tprintf(" <%ld.%06ld>",
2380 (long) tv.tv_sec, (long) tv.tv_usec);
2381 }
2382 printtrailer(tcp);
2383
2384 dumpio(tcp);
2385 if (fflush(tcp->outf) == EOF)
2386 return -1;
2387 tcp->flags &= ~TCB_INSYSCALL;
2388 return 0;
2389 }
2390
2391 /* Entering system call */
2392 res = syscall_enter(tcp);
2393 if (res != 1)
2394 return res;
2395
Roland McGrath17352792005-06-07 23:21:26 +00002396 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002397#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002398#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002399 case SYS_socketcall:
2400 decode_subcall(tcp, SYS_socket_subcall,
2401 SYS_socket_nsubcalls, deref_style);
2402 break;
2403 case SYS_ipc:
2404 decode_subcall(tcp, SYS_ipc_subcall,
2405 SYS_ipc_nsubcalls, shift_style);
2406 break;
Roland McGrath17352792005-06-07 23:21:26 +00002407#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002408#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002409 case SYS_socketcall:
2410 sparc_socket_decode (tcp);
2411 break;
2412#endif
2413#endif /* LINUX */
2414#ifdef SVR4
2415#ifdef SYS_pgrpsys_subcall
2416 case SYS_pgrpsys:
2417 decode_subcall(tcp, SYS_pgrpsys_subcall,
2418 SYS_pgrpsys_nsubcalls, shift_style);
2419 break;
2420#endif /* SYS_pgrpsys_subcall */
2421#ifdef SYS_sigcall_subcall
2422 case SYS_sigcall:
2423 decode_subcall(tcp, SYS_sigcall_subcall,
2424 SYS_sigcall_nsubcalls, mask_style);
2425 break;
2426#endif /* SYS_sigcall_subcall */
2427 case SYS_msgsys:
2428 decode_subcall(tcp, SYS_msgsys_subcall,
2429 SYS_msgsys_nsubcalls, shift_style);
2430 break;
2431 case SYS_shmsys:
2432 decode_subcall(tcp, SYS_shmsys_subcall,
2433 SYS_shmsys_nsubcalls, shift_style);
2434 break;
2435 case SYS_semsys:
2436 decode_subcall(tcp, SYS_semsys_subcall,
2437 SYS_semsys_nsubcalls, shift_style);
2438 break;
2439#if 0 /* broken */
2440 case SYS_utssys:
2441 decode_subcall(tcp, SYS_utssys_subcall,
2442 SYS_utssys_nsubcalls, shift_style);
2443 break;
2444#endif
2445 case SYS_sysfs:
2446 decode_subcall(tcp, SYS_sysfs_subcall,
2447 SYS_sysfs_nsubcalls, shift_style);
2448 break;
2449 case SYS_spcall:
2450 decode_subcall(tcp, SYS_spcall_subcall,
2451 SYS_spcall_nsubcalls, shift_style);
2452 break;
2453#ifdef SYS_context_subcall
2454 case SYS_context:
2455 decode_subcall(tcp, SYS_context_subcall,
2456 SYS_context_nsubcalls, shift_style);
2457 break;
2458#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002459#ifdef SYS_door_subcall
2460 case SYS_door:
2461 decode_subcall(tcp, SYS_door_subcall,
2462 SYS_door_nsubcalls, door_style);
2463 break;
2464#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002465#ifdef SYS_kaio_subcall
2466 case SYS_kaio:
2467 decode_subcall(tcp, SYS_kaio_subcall,
2468 SYS_kaio_nsubcalls, shift_style);
2469 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002470#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002471#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002472#ifdef FREEBSD
2473 case SYS_msgsys:
2474 case SYS_shmsys:
2475 case SYS_semsys:
2476 decode_subcall(tcp, 0, 0, table_style);
2477 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002478#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002479#ifdef SUNOS4
2480 case SYS_semsys:
2481 decode_subcall(tcp, SYS_semsys_subcall,
2482 SYS_semsys_nsubcalls, shift_style);
2483 break;
2484 case SYS_msgsys:
2485 decode_subcall(tcp, SYS_msgsys_subcall,
2486 SYS_msgsys_nsubcalls, shift_style);
2487 break;
2488 case SYS_shmsys:
2489 decode_subcall(tcp, SYS_shmsys_subcall,
2490 SYS_shmsys_nsubcalls, shift_style);
2491 break;
2492#endif
2493 }
2494
2495 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002496 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002497 tcp->flags |= TCB_INSYSCALL;
2498 return 0;
2499 }
2500
2501 if (cflag) {
2502 gettimeofday(&tcp->etime, NULL);
2503 tcp->flags |= TCB_INSYSCALL;
2504 return 0;
2505 }
2506
2507 printleader(tcp);
2508 tcp->flags &= ~TCB_REPRINT;
2509 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002510 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511 tprintf("syscall_%lu(", tcp->scno);
2512 else
2513 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002514 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002515 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2516 sys_res = printargs(tcp);
2517 else
2518 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2519 if (fflush(tcp->outf) == EOF)
2520 return -1;
2521 tcp->flags |= TCB_INSYSCALL;
2522 /* Measure the entrance time as late as possible to avoid errors. */
2523 if (dtime)
2524 gettimeofday(&tcp->etime, NULL);
2525 return sys_res;
2526}
2527
2528int
2529printargs(tcp)
2530struct tcb *tcp;
2531{
2532 if (entering(tcp)) {
2533 int i;
2534
2535 for (i = 0; i < tcp->u_nargs; i++)
2536 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2537 }
2538 return 0;
2539}
2540
2541long
2542getrval2(tcp)
2543struct tcb *tcp;
2544{
2545 long val = -1;
2546
2547#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002548#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002549 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002550 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2551 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002552 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002553#elif defined(SH)
2554 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2555 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002556#elif defined(IA64)
2557 if (upeek(tcp->pid, PT_R9, &val) < 0)
2558 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002559#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002560#endif /* LINUX */
2561
2562#ifdef SUNOS4
2563 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2564 return -1;
2565#endif /* SUNOS4 */
2566
2567#ifdef SVR4
2568#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002569 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570#endif /* SPARC */
2571#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002572 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002573#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002574#ifdef X86_64
2575 val = tcp->status.PR_REG[RDX];
2576#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002578 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002579#endif /* MIPS */
2580#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002581#ifdef FREEBSD
2582 struct reg regs;
2583 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2584 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002585#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002586 return val;
2587}
2588
2589/*
2590 * Apparently, indirect system calls have already be converted by ptrace(2),
2591 * so if you see "indir" this program has gone astray.
2592 */
2593int
2594sys_indir(tcp)
2595struct tcb *tcp;
2596{
2597 int i, scno, nargs;
2598
2599 if (entering(tcp)) {
2600 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2601 fprintf(stderr, "Bogus syscall: %u\n", scno);
2602 return 0;
2603 }
2604 nargs = sysent[scno].nargs;
2605 tprintf("%s", sysent[scno].sys_name);
2606 for (i = 0; i < nargs; i++)
2607 tprintf(", %#lx", tcp->u_arg[i+1]);
2608 }
2609 return 0;
2610}
2611
2612static int
2613time_cmp(a, b)
2614void *a;
2615void *b;
2616{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002617 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002618}
2619
2620static int
2621syscall_cmp(a, b)
2622void *a;
2623void *b;
2624{
2625 return strcmp(sysent[*((int *) a)].sys_name,
2626 sysent[*((int *) b)].sys_name);
2627}
2628
2629static int
2630count_cmp(a, b)
2631void *a;
2632void *b;
2633{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002634 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635
2636 return (m < n) ? 1 : (m > n) ? -1 : 0;
2637}
2638
2639static int (*sortfun)();
2640static struct timeval overhead = { -1, -1 };
2641
2642void
2643set_sortby(sortby)
2644char *sortby;
2645{
2646 if (strcmp(sortby, "time") == 0)
2647 sortfun = time_cmp;
2648 else if (strcmp(sortby, "calls") == 0)
2649 sortfun = count_cmp;
2650 else if (strcmp(sortby, "name") == 0)
2651 sortfun = syscall_cmp;
2652 else if (strcmp(sortby, "nothing") == 0)
2653 sortfun = NULL;
2654 else {
2655 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2656 exit(1);
2657 }
2658}
2659
2660void set_overhead(n)
2661int n;
2662{
2663 overhead.tv_sec = n / 1000000;
2664 overhead.tv_usec = n % 1000000;
2665}
2666
2667void
2668call_summary(outf)
2669FILE *outf;
2670{
2671 int i, j;
2672 int call_cum, error_cum;
2673 struct timeval tv_cum, dtv;
2674 double percent;
2675 char *dashes = "-------------------------";
2676 char error_str[16];
2677
Roland McGrathe10e62a2004-09-04 04:20:43 +00002678 int *sorted_count = malloc(nsyscalls * sizeof(int));
2679
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002680 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2681 if (overhead.tv_sec == -1) {
2682 tv_mul(&overhead, &shortest, 8);
2683 tv_div(&overhead, &overhead, 10);
2684 }
2685 for (i = 0; i < nsyscalls; i++) {
2686 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002687 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002689 tv_mul(&dtv, &overhead, counts[i].calls);
2690 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2691 call_cum += counts[i].calls;
2692 error_cum += counts[i].errors;
2693 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002695 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2697 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2698 "% time", "seconds", "usecs/call",
2699 "calls", "errors", "syscall");
2700 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2701 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002702 if (counts) {
2703 for (i = 0; i < nsyscalls; i++) {
2704 j = sorted_count[i];
2705 if (counts[j].calls == 0)
2706 continue;
2707 tv_div(&dtv, &counts[j].time, counts[j].calls);
2708 if (counts[j].errors)
2709 sprintf(error_str, "%d", counts[j].errors);
2710 else
2711 error_str[0] = '\0';
2712 percent = (100.0 * tv_float(&counts[j].time)
2713 / tv_float(&tv_cum));
2714 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2715 percent, (long) counts[j].time.tv_sec,
2716 (long) counts[j].time.tv_usec,
2717 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2718 counts[j].calls,
2719 error_str, sysent[j].sys_name);
2720 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002721 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002722 free(sorted_count);
2723
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2725 dashes, dashes, dashes, dashes, dashes, dashes);
2726 if (error_cum)
2727 sprintf(error_str, "%d", error_cum);
2728 else
2729 error_str[0] = '\0';
2730 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2731 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2732 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734}