blob: 241dfa452433d507c28ecb7ee304779b99d0fe0f [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
296 for (i = 0; i < nsyscalls; i++) {
297 if (strcmp(s, sysent[i].sys_name) == 0) {
298 qualify_one(i, opt, not);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000299 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000300 }
301 }
Roland McGrathfe6b3522005-02-02 04:40:11 +0000302 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000303}
304
305static int
306qual_signal(s, opt, not)
307 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000308 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000309 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000310{
311 int i;
312 char buf[32];
313
Roland McGrathfe6b3522005-02-02 04:40:11 +0000314 if (s && *s && isdigit((unsigned char)*s)) {
315 int signo = atoi(s);
316 if (signo < 0 || signo >= MAX_QUALS)
317 return -1;
318 qualify_one(signo, opt, not);
319 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000321 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000322 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000323 strcpy(buf, s);
324 s = buf;
325 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000326 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000327 if (strncmp(s, "SIG", 3) == 0)
328 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000329 for (i = 0; i <= NSIG; i++)
330 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath76421df2005-02-02 03:51:18 +0000331 qualify_one(i, opt, not);
332 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000333 }
Roland McGrath76421df2005-02-02 03:51:18 +0000334 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000335}
336
337static int
338qual_fault(s, opt, not)
339 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000340 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000341 int not;
342{
343 return -1;
344}
345
346static int
347qual_desc(s, opt, not)
348 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000349 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000350 int not;
351{
352 if (s && *s && isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 int desc = atoi(s);
354 if (desc < 0 || desc >= MAX_QUALS)
355 return -1;
356 qualify_one(desc, opt, not);
Roland McGrath2b619022003-04-10 18:58:20 +0000357 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000358 }
359 return -1;
360}
361
362static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000364 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000365{
366 if (strcmp(s, "file") == 0)
367 return TRACE_FILE;
368 if (strcmp(s, "ipc") == 0)
369 return TRACE_IPC;
370 if (strcmp(s, "network") == 0)
371 return TRACE_NETWORK;
372 if (strcmp(s, "process") == 0)
373 return TRACE_PROCESS;
374 if (strcmp(s, "signal") == 0)
375 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000376 if (strcmp(s, "desc") == 0)
377 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378 return -1;
379}
380
381void
382qualify(s)
383char *s;
384{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000385 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 int not;
387 char *p;
388 int i, n;
389
390 opt = &qual_options[0];
391 for (i = 0; (p = qual_options[i].option_name); i++) {
392 n = strlen(p);
393 if (strncmp(s, p, n) == 0 && s[n] == '=') {
394 opt = &qual_options[i];
395 s += n + 1;
396 break;
397 }
398 }
399 not = 0;
400 if (*s == '!') {
401 not = 1;
402 s++;
403 }
404 if (strcmp(s, "none") == 0) {
405 not = 1 - not;
406 s = "all";
407 }
408 if (strcmp(s, "all") == 0) {
409 for (i = 0; i < MAX_QUALS; i++) {
410 if (not)
411 qual_flags[i] &= ~opt->bitflag;
412 else
413 qual_flags[i] |= opt->bitflag;
414 }
415 return;
416 }
417 for (i = 0; i < MAX_QUALS; i++) {
418 if (not)
419 qual_flags[i] |= opt->bitflag;
420 else
421 qual_flags[i] &= ~opt->bitflag;
422 }
423 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
424 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
425 for (i = 0; i < MAX_QUALS; i++) {
426 if (sysent[i].sys_flags & n) {
427 if (not)
428 qual_flags[i] &= ~opt->bitflag;
429 else
430 qual_flags[i] |= opt->bitflag;
431 }
432 }
433 continue;
434 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000435 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 fprintf(stderr, "strace: invalid %s `%s'\n",
437 opt->argument_name, p);
438 exit(1);
439 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440 }
441 return;
442}
443
444static void
445dumpio(tcp)
446struct tcb *tcp;
447{
448 if (syserror(tcp))
449 return;
450 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
451 return;
Roland McGrath17352792005-06-07 23:21:26 +0000452 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000453 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000454#ifdef SYS_pread64
455 case SYS_pread64:
456#endif
457#if defined SYS_pread && SYS_pread64 != SYS_pread
458 case SYS_pread:
459#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460#ifdef SYS_recv
461 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000462#elif defined SYS_sub_recv
463 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464#endif
465#ifdef SYS_recvfrom
466 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000467#elif defined SYS_sub_recvfrom
468 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469#endif
470 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
471 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
472 break;
473 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000474#ifdef SYS_pwrite64
475 case SYS_pwrite64:
476#endif
477#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
478 case SYS_pwrite:
479#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000480#ifdef SYS_send
481 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000482#elif defined SYS_sub_send
483 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484#endif
485#ifdef SYS_sendto
486 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000487#elif defined SYS_sub_sendto
488 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000489#endif
490 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
491 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
492 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000493#ifdef SYS_readv
494 case SYS_readv:
495 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
496 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
497 break;
498#endif
499#ifdef SYS_writev
500 case SYS_writev:
501
502 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
503 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
504 break;
505#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000506 }
507}
508
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000509#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000510enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000511#else /* FREEBSD */
512enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
513
514struct subcall {
515 int call;
516 int nsubcalls;
517 int subcalls[5];
518};
519
Roland McGratha4d48532005-06-08 20:45:28 +0000520static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000521 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000522#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000523 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000524#else
525 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
526#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000527 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
528};
529#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000531#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000532
Roland McGratha4d48532005-06-08 20:45:28 +0000533static const int socket_map [] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534 /* SYS_SOCKET */ 97,
535 /* SYS_BIND */ 104,
536 /* SYS_CONNECT */ 98,
537 /* SYS_LISTEN */ 106,
538 /* SYS_ACCEPT */ 99,
539 /* SYS_GETSOCKNAME */ 150,
540 /* SYS_GETPEERNAME */ 141,
541 /* SYS_SOCKETPAIR */ 135,
542 /* SYS_SEND */ 101,
543 /* SYS_RECV */ 102,
544 /* SYS_SENDTO */ 133,
545 /* SYS_RECVFROM */ 125,
546 /* SYS_SHUTDOWN */ 134,
547 /* SYS_SETSOCKOPT */ 105,
548 /* SYS_GETSOCKOPT */ 118,
549 /* SYS_SENDMSG */ 114,
550 /* SYS_RECVMSG */ 113
551};
552
Roland McGratha4d48532005-06-08 20:45:28 +0000553#if defined (SPARC) || defined (SPARC64)
554static void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000555sparc_socket_decode (tcp)
556struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557{
558 volatile long addr;
559 volatile int i, n;
560
561 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
562 return;
563 }
564 tcp->scno = socket_map [tcp->u_arg [0]-1];
565 n = tcp->u_nargs = sysent [tcp->scno].nargs;
566 addr = tcp->u_arg [1];
567 for (i = 0; i < n; i++){
568 int arg;
569 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
570 arg = 0;
571 tcp->u_arg [i] = arg;
572 addr += sizeof (arg);
573 }
574}
Roland McGratha4d48532005-06-08 20:45:28 +0000575#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576
Roland McGratha4d48532005-06-08 20:45:28 +0000577static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578decode_subcall(tcp, subcall, nsubcalls, style)
579struct tcb *tcp;
580int subcall;
581int nsubcalls;
582enum subcall_style style;
583{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000584 long addr, mask, arg;
585 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000586
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587 switch (style) {
588 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000589 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
590 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591 tcp->scno = subcall + tcp->u_arg[0];
592 if (sysent[tcp->scno].nargs != -1)
593 tcp->u_nargs = sysent[tcp->scno].nargs;
594 else
595 tcp->u_nargs--;
596 for (i = 0; i < tcp->u_nargs; i++)
597 tcp->u_arg[i] = tcp->u_arg[i + 1];
598 break;
599 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000600 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
601 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 tcp->scno = subcall + tcp->u_arg[0];
603 addr = tcp->u_arg[1];
604 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
605 if (umove(tcp, addr, &arg) < 0)
606 arg = 0;
607 tcp->u_arg[i] = arg;
608 addr += sizeof(arg);
609 }
610 tcp->u_nargs = sysent[tcp->scno].nargs;
611 break;
612 case mask_style:
613 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 for (i = 0; mask; i++)
615 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000616 if (i >= nsubcalls)
617 return;
618 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 tcp->scno = subcall + i;
620 if (sysent[tcp->scno].nargs != -1)
621 tcp->u_nargs = sysent[tcp->scno].nargs;
622 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000623 case door_style:
624 /*
625 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000626 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000627 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000628 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
629 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000630 tcp->scno = subcall + tcp->u_arg[5];
631 if (sysent[tcp->scno].nargs != -1)
632 tcp->u_nargs = sysent[tcp->scno].nargs;
633 else
634 tcp->u_nargs--;
635 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000636#ifdef FREEBSD
637 case table_style:
638 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
639 if (subcalls_table[i].call == tcp->scno) break;
640 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
641 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
642 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
643 for (i = 0; i < tcp->u_nargs; i++)
644 tcp->u_arg[i] = tcp->u_arg[i + 1];
645 }
646 break;
647#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 }
649}
650#endif
651
652struct tcb *tcp_last = NULL;
653
654static int
655internal_syscall(tcp)
656struct tcb *tcp;
657{
658 /*
659 * We must always trace a few critical system calls in order to
660 * correctly support following forks in the presence of tracing
661 * qualifiers.
662 */
Roland McGrath17352792005-06-07 23:21:26 +0000663 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000664#ifdef SYS_fork
665 case SYS_fork:
666#endif
667#ifdef SYS_vfork
668 case SYS_vfork:
669#endif
John Hughes4e36a812001-04-18 15:11:51 +0000670#ifdef SYS_fork1
671 case SYS_fork1:
672#endif
673#ifdef SYS_forkall
674 case SYS_forkall:
675#endif
676#ifdef SYS_rfork1
677 case SYS_rfork1:
678#endif
679#ifdef SYS_rforkall
680 case SYS_rforkall:
681#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000682#ifdef SYS_rfork
683 case SYS_rfork:
684#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685 internal_fork(tcp);
686 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000687#ifdef SYS_clone
688 case SYS_clone:
689 internal_clone(tcp);
690 break;
691#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000692#ifdef SYS_clone2
693 case SYS_clone2:
694 internal_clone(tcp);
695 break;
696#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697#ifdef SYS_execv
698 case SYS_execv:
699#endif
700#ifdef SYS_execve
701 case SYS_execve:
702#endif
John Hughes4e36a812001-04-18 15:11:51 +0000703#ifdef SYS_rexecve
704 case SYS_rexecve:
705#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706 internal_exec(tcp);
707 break;
708
709#ifdef SYS_wait
710 case SYS_wait:
711#endif
712#ifdef SYS_wait4
713 case SYS_wait4:
714#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000715#ifdef SYS32_wait4
716 case SYS32_wait4:
717#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000718#ifdef SYS_waitpid
719 case SYS_waitpid:
720#endif
721#ifdef SYS_waitsys
722 case SYS_waitsys:
723#endif
Roland McGrathc74c0b72004-09-01 19:39:46 +0000724 internal_wait(tcp, 2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 break;
Roland McGrathc74c0b72004-09-01 19:39:46 +0000726#ifdef SYS_waitid
727 case SYS_waitid:
728 internal_wait(tcp, 3);
729 break;
730#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731
732#ifdef SYS_exit
733 case SYS_exit:
734#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000735#ifdef SYS32_exit
736 case SYS32_exit:
737#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000738#ifdef __NR_exit_group
739 case __NR_exit_group:
740#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000741#ifdef IA64
742 case 252: /* IA-32 __NR_exit_group */
743#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744 internal_exit(tcp);
745 break;
746 }
747 return 0;
748}
749
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750
751#ifdef LINUX
752#if defined (I386)
753 static long eax;
754#elif defined (IA64)
755 long r8, r10, psr;
756 long ia32 = 0;
757#elif defined (POWERPC)
758 static long result,flags;
759#elif defined (M68K)
760 static int d0;
761#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000762 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000763#elif defined (ALPHA)
764 static long r0;
765 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000766#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000767 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000768 static unsigned long trap;
769#elif defined(MIPS)
770 static long a3;
771 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000772#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000773 static long gpr2;
774 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000775 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000776#elif defined(HPPA)
777 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000778#elif defined(SH)
779 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000780#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000781 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000782#elif defined(X86_64)
783 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000784#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000785#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000786#ifdef FREEBSD
787 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000788#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000789
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000791get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792struct tcb *tcp;
793{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000795#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000797#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000800#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000801 if (tcp->flags & TCB_WAITEXECVE) {
802 /*
803 * When the execve system call completes successfully, the
804 * new process still has -ENOSYS (old style) or __NR_execve
805 * (new style) in gpr2. We cannot recover the scno again
806 * by disassembly, because the image that executed the
807 * syscall is gone now. Fortunately, we don't want it. We
808 * leave the flag set so that syscall_fixup can fake the
809 * result.
810 */
811 if (tcp->flags & TCB_INSYSCALL)
812 return 1;
813 /*
814 * This is the SIGTRAP after execve. We cannot try to read
815 * the system call here either.
816 */
817 tcp->flags &= ~TCB_WAITEXECVE;
818 return 0;
819 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000820
821 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
822 return -1;
823
824 if (syscall_mode != -ENOSYS) {
825 /*
826 * Since kernel version 2.5.44 the scno gets passed in gpr2.
827 */
828 scno = syscall_mode;
829 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000830 /*
831 * Old style of "passing" the scno via the SVC instruction.
832 */
833
834 long opcode, offset_reg, tmp;
835 void * svc_addr;
836 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
837 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
838 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
839 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000840
Michal Ludvig882eda82002-11-11 12:50:47 +0000841 if (upeek(pid, PT_PSWADDR, &pc) < 0)
842 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000843 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000844 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000845 if (errno) {
846 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000848 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000849
850 /*
851 * We have to check if the SVC got executed directly or via an
852 * EXECUTE instruction. In case of EXECUTE it is necessary to do
853 * instruction decoding to derive the system call number.
854 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
855 * so that this doesn't work if a SVC opcode is part of an EXECUTE
856 * opcode. Since there is no way to find out the opcode size this
857 * is the best we can do...
858 */
859
860 if ((opcode & 0xff00) == 0x0a00) {
861 /* SVC opcode */
862 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000863 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000864 else {
865 /* SVC got executed by EXECUTE instruction */
866
867 /*
868 * Do instruction decoding of EXECUTE. If you really want to
869 * understand this, read the Principles of Operations.
870 */
871 svc_addr = (void *) (opcode & 0xfff);
872
873 tmp = 0;
874 offset_reg = (opcode & 0x000f0000) >> 16;
875 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
876 return -1;
877 svc_addr += tmp;
878
879 tmp = 0;
880 offset_reg = (opcode & 0x0000f000) >> 12;
881 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
882 return -1;
883 svc_addr += tmp;
884
885 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
886 if (errno)
887 return -1;
888#if defined(S390X)
889 scno >>= 48;
890#else
891 scno >>= 16;
892#endif
893 tmp = 0;
894 offset_reg = (opcode & 0x00f00000) >> 20;
895 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
896 return -1;
897
898 scno = (scno | tmp) & 0xff;
899 }
900 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000901#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000902 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 return -1;
904 if (!(tcp->flags & TCB_INSYSCALL)) {
905 /* Check if we return from execve. */
906 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
907 tcp->flags &= ~TCB_WAITEXECVE;
908 return 0;
909 }
910 }
911#elif defined (I386)
912 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
913 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000914#elif defined (X86_64)
915 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
916 return -1;
917
Roland McGrath761b5d72002-12-15 23:58:31 +0000918 if (!(tcp->flags & TCB_INSYSCALL)) {
919 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000920 long val;
921
922 /* Check CS register value. On x86-64 linux it is:
923 * 0x33 for long mode (64 bit)
924 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000925 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000926 * to be cached.
927 */
928 if (upeek(pid, 8*CS, &val) < 0)
929 return -1;
930 switch(val)
931 {
932 case 0x23: currpers = 1; break;
933 case 0x33: currpers = 0; break;
934 default:
935 fprintf(stderr, "Unknown value CS=0x%02X while "
936 "detecting personality of process "
937 "PID=%d\n", (int)val, pid);
938 currpers = current_personality;
939 break;
940 }
941#if 0
942 /* This version analyzes the opcode of a syscall instruction.
943 * (int 0x80 on i386 vs. syscall on x86-64)
944 * It works, but is too complicated.
945 */
946 unsigned long val, rip, i;
947
948 if(upeek(pid, 8*RIP, &rip)<0)
949 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000950
Michal Ludvig0e035502002-09-23 15:41:01 +0000951 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
952 rip-=2;
953 errno = 0;
954
Roland McGrath761b5d72002-12-15 23:58:31 +0000955 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
956 if (errno)
957 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000958 strerror(errno));
959 switch (call & 0xffff)
960 {
961 /* x86-64: syscall = 0x0f 0x05 */
962 case 0x050f: currpers = 0; break;
963 /* i386: int 0x80 = 0xcd 0x80 */
964 case 0x80cd: currpers = 1; break;
965 default:
966 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000967 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000968 "Unknown syscall opcode (0x%04X) while "
969 "detecting personality of process "
970 "PID=%d\n", (int)call, pid);
971 break;
972 }
973#endif
974 if(currpers != current_personality)
975 {
976 char *names[]={"64 bit", "32 bit"};
977 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000978 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000979 pid, names[current_personality]);
980 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000981 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000982#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000983# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000985 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000986 if (!(tcp->flags & TCB_INSYSCALL)) {
987 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000988 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000989 return -1;
990 } else {
991 if (upeek (pid, PT_R15, &scno) < 0)
992 return -1;
993 }
Roland McGrathba954762003-03-05 06:29:06 +0000994 /* Check if we return from execve. */
995 if (tcp->flags & TCB_WAITEXECVE) {
996 tcp->flags &= ~TCB_WAITEXECVE;
997 return 0;
998 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 } else {
1000 /* syscall in progress */
1001 if (upeek (pid, PT_R8, &r8) < 0)
1002 return -1;
1003 if (upeek (pid, PT_R10, &r10) < 0)
1004 return -1;
1005 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001007 /*
1008 * Read complete register set in one go.
1009 */
1010 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1011 return -1;
1012
1013 /*
1014 * We only need to grab the syscall number on syscall entry.
1015 */
1016 if (regs.ARM_ip == 0) {
1017 /*
1018 * Note: we only deal with only 32-bit CPUs here.
1019 */
1020 if (regs.ARM_cpsr & 0x20) {
1021 /*
1022 * Get the Thumb-mode system call number
1023 */
1024 scno = regs.ARM_r7;
1025 } else {
1026 /*
1027 * Get the ARM-mode system call number
1028 */
1029 errno = 0;
1030 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1031 if (errno)
1032 return -1;
1033
1034 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1035 tcp->flags &= ~TCB_WAITEXECVE;
1036 return 0;
1037 }
1038
1039 if ((scno & 0x0ff00000) != 0x0f900000) {
1040 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1041 scno);
1042 return -1;
1043 }
1044
1045 /*
1046 * Fixup the syscall number
1047 */
1048 scno &= 0x000fffff;
1049 }
1050
1051 if (tcp->flags & TCB_INSYSCALL) {
1052 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1053 tcp->flags &= ~TCB_INSYSCALL;
1054 }
1055 } else {
1056 if (!(tcp->flags & TCB_INSYSCALL)) {
1057 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1058 tcp->flags |= TCB_INSYSCALL;
1059 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 }
1061#elif defined (M68K)
1062 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1063 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001064#elif defined (MIPS)
1065 if (upeek(pid, REG_A3, &a3) < 0)
1066 return -1;
1067
1068 if(!(tcp->flags & TCB_INSYSCALL)) {
1069 if (upeek(pid, REG_V0, &scno) < 0)
1070 return -1;
1071
1072 if (scno < 0 || scno > nsyscalls) {
1073 if(a3 == 0 || a3 == -1) {
1074 if(debug)
1075 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1076 return 0;
1077 }
1078 }
1079 } else {
1080 if (upeek(pid, REG_V0, &r2) < 0)
1081 return -1;
1082 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083#elif defined (ALPHA)
1084 if (upeek(pid, REG_A3, &a3) < 0)
1085 return -1;
1086
1087 if (!(tcp->flags & TCB_INSYSCALL)) {
1088 if (upeek(pid, REG_R0, &scno) < 0)
1089 return -1;
1090
1091 /* Check if we return from execve. */
1092 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1093 tcp->flags &= ~TCB_WAITEXECVE;
1094 return 0;
1095 }
1096
1097 /*
1098 * Do some sanity checks to figure out if it's
1099 * really a syscall entry
1100 */
1101 if (scno < 0 || scno > nsyscalls) {
1102 if (a3 == 0 || a3 == -1) {
1103 if (debug)
1104 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1105 return 0;
1106 }
1107 }
1108 }
1109 else {
1110 if (upeek(pid, REG_R0, &r0) < 0)
1111 return -1;
1112 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001113#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 /* Everything we need is in the current register set. */
1115 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1116 return -1;
1117
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 /* If we are entering, then disassemble the syscall trap. */
1119 if (!(tcp->flags & TCB_INSYSCALL)) {
1120 /* Retrieve the syscall trap instruction. */
1121 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001122 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001123#if defined(SPARC64)
1124 trap >>= 32;
1125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 if (errno)
1127 return -1;
1128
1129 /* Disassemble the trap to see what personality to use. */
1130 switch (trap) {
1131 case 0x91d02010:
1132 /* Linux/SPARC syscall trap. */
1133 set_personality(0);
1134 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001135 case 0x91d0206d:
1136 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001137 set_personality(2);
1138 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 case 0x91d02000:
1140 /* SunOS syscall trap. (pers 1) */
1141 fprintf(stderr,"syscall: SunOS no support\n");
1142 return -1;
1143 case 0x91d02008:
1144 /* Solaris 2.x syscall trap. (per 2) */
1145 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001146 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 case 0x91d02009:
1148 /* NetBSD/FreeBSD syscall trap. */
1149 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1150 return -1;
1151 case 0x91d02027:
1152 /* Solaris 2.x gettimeofday */
1153 set_personality(1);
1154 break;
1155 default:
1156 /* Unknown syscall trap. */
1157 if(tcp->flags & TCB_WAITEXECVE) {
1158 tcp->flags &= ~TCB_WAITEXECVE;
1159 return 0;
1160 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001161#if defined (SPARC64)
1162 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1163#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001164 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001165#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 return -1;
1167 }
1168
1169 /* Extract the system call number from the registers. */
1170 if (trap == 0x91d02027)
1171 scno = 156;
1172 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001173 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001175 scno = regs.r_o0;
1176 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 }
1178 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001179#elif defined(HPPA)
1180 if (upeek(pid, PT_GR20, &scno) < 0)
1181 return -1;
1182 if (!(tcp->flags & TCB_INSYSCALL)) {
1183 /* Check if we return from execve. */
1184 if ((tcp->flags & TCB_WAITEXECVE)) {
1185 tcp->flags &= ~TCB_WAITEXECVE;
1186 return 0;
1187 }
1188 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001189#elif defined(SH)
1190 /*
1191 * In the new syscall ABI, the system call number is in R3.
1192 */
1193 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1194 return -1;
1195
1196 if (scno < 0) {
1197 /* Odd as it may seem, a glibc bug has been known to cause
1198 glibc to issue bogus negative syscall numbers. So for
1199 our purposes, make strace print what it *should* have been */
1200 long correct_scno = (scno & 0xff);
1201 if (debug)
1202 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001203 "Detected glibc bug: bogus system call number = %ld, "
1204 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001205 scno,
1206 correct_scno);
1207 scno = correct_scno;
1208 }
1209
1210
1211 if (!(tcp->flags & TCB_INSYSCALL)) {
1212 /* Check if we return from execve. */
1213 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1214 tcp->flags &= ~TCB_WAITEXECVE;
1215 return 0;
1216 }
1217 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001218#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001219 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1220 return -1;
1221 scno &= 0xFFFF;
1222
1223 if (!(tcp->flags & TCB_INSYSCALL)) {
1224 /* Check if we return from execve. */
1225 if (tcp->flags & TCB_WAITEXECVE) {
1226 tcp->flags &= ~TCB_WAITEXECVE;
1227 return 0;
1228 }
1229 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001230#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231#endif /* LINUX */
1232#ifdef SUNOS4
1233 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1234 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001235#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001236 /* new syscall ABI returns result in R0 */
1237 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1238 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001239#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001240 /* ABI defines result returned in r9 */
1241 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1242 return -1;
1243
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001247 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001250 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001251#else /* FREEBSD */
1252 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1253 perror("pread");
1254 return -1;
1255 }
1256 switch (regs.r_eax) {
1257 case SYS_syscall:
1258 case SYS___syscall:
1259 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1260 break;
1261 default:
1262 scno = regs.r_eax;
1263 break;
1264 }
1265#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001267#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001268 if (!(tcp->flags & TCB_INSYSCALL))
1269 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001270 return 1;
1271}
1272
Pavel Machek4dc3b142000-02-01 17:58:41 +00001273
Roland McGrath17352792005-06-07 23:21:26 +00001274long
1275known_scno(tcp)
1276struct tcb *tcp;
1277{
1278 long scno = tcp->scno;
1279 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1280 scno = sysent[scno].native_scno;
1281 else
1282 scno += NR_SYSCALL_BASE;
1283 return scno;
1284}
1285
Roland McGratha4d48532005-06-08 20:45:28 +00001286static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001287syscall_fixup(tcp)
1288struct tcb *tcp;
1289{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001290#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001291 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001292#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001293 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001294
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001296 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297 if (
1298 scno == SYS_fork
1299#ifdef SYS_vfork
1300 || scno == SYS_vfork
1301#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001302#ifdef SYS_fork1
1303 || scno == SYS_fork1
1304#endif /* SYS_fork1 */
1305#ifdef SYS_forkall
1306 || scno == SYS_forkall
1307#endif /* SYS_forkall */
1308#ifdef SYS_rfork1
1309 || scno == SYS_rfork1
1310#endif /* SYS_fork1 */
1311#ifdef SYS_rforkall
1312 || scno == SYS_rforkall
1313#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314 ) {
1315 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001316 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001318 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001319 }
1320 else {
1321 fprintf(stderr, "syscall: missing entry\n");
1322 tcp->flags |= TCB_INSYSCALL;
1323 }
1324 }
1325 }
1326 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001327 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328 fprintf(stderr, "syscall: missing exit\n");
1329 tcp->flags &= ~TCB_INSYSCALL;
1330 }
1331 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001332#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333#ifdef SUNOS4
1334 if (!(tcp->flags & TCB_INSYSCALL)) {
1335 if (scno == 0) {
1336 fprintf(stderr, "syscall: missing entry\n");
1337 tcp->flags |= TCB_INSYSCALL;
1338 }
1339 }
1340 else {
1341 if (scno != 0) {
1342 if (debug) {
1343 /*
1344 * This happens when a signal handler
1345 * for a signal which interrupted a
1346 * a system call makes another system call.
1347 */
1348 fprintf(stderr, "syscall: missing exit\n");
1349 }
1350 tcp->flags &= ~TCB_INSYSCALL;
1351 }
1352 }
1353#endif /* SUNOS4 */
1354#ifdef LINUX
1355#if defined (I386)
1356 if (upeek(pid, 4*EAX, &eax) < 0)
1357 return -1;
1358 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1359 if (debug)
1360 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1361 return 0;
1362 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001363#elif defined (X86_64)
1364 if (upeek(pid, 8*RAX, &rax) < 0)
1365 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001366 if (current_personality == 1)
1367 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001368 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1369 if (debug)
1370 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1371 return 0;
1372 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001373#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001374 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1375 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001376 if (syscall_mode != -ENOSYS)
1377 syscall_mode = tcp->scno;
1378 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001379 if (debug)
1380 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1381 return 0;
1382 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001383 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1384 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1385 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1386 /*
1387 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1388 * flag set for the post-execve SIGTRAP to see and reset.
1389 */
1390 gpr2 = 0;
1391 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392#elif defined (POWERPC)
1393# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001394 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001396 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 return -1;
1398 if (flags & SO_MASK)
1399 result = -result;
1400#elif defined (M68K)
1401 if (upeek(pid, 4*PT_D0, &d0) < 0)
1402 return -1;
1403 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1404 if (debug)
1405 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1406 return 0;
1407 }
1408#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001409 /*
1410 * Nothing required
1411 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001412#elif defined (HPPA)
1413 if (upeek(pid, PT_GR28, &r28) < 0)
1414 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001415#elif defined(IA64)
1416 if (upeek(pid, PT_R10, &r10) < 0)
1417 return -1;
1418 if (upeek(pid, PT_R8, &r8) < 0)
1419 return -1;
1420 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1421 if (debug)
1422 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1423 return 0;
1424 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001425#endif
1426#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001427 return 1;
1428}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429
Roland McGratha4d48532005-06-08 20:45:28 +00001430static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001431get_error(tcp)
1432struct tcb *tcp;
1433{
1434 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001436#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001437 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1438 tcp->u_rval = -1;
1439 u_error = -gpr2;
1440 }
1441 else {
1442 tcp->u_rval = gpr2;
1443 u_error = 0;
1444 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001445#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446#ifdef I386
1447 if (eax < 0 && -eax < nerrnos) {
1448 tcp->u_rval = -1;
1449 u_error = -eax;
1450 }
1451 else {
1452 tcp->u_rval = eax;
1453 u_error = 0;
1454 }
1455#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001456#ifdef X86_64
1457 if (rax < 0 && -rax < nerrnos) {
1458 tcp->u_rval = -1;
1459 u_error = -rax;
1460 }
1461 else {
1462 tcp->u_rval = rax;
1463 u_error = 0;
1464 }
1465#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001466#ifdef IA64
1467 if (ia32) {
1468 int err;
1469
1470 err = (int)r8;
1471 if (err < 0 && -err < nerrnos) {
1472 tcp->u_rval = -1;
1473 u_error = -err;
1474 }
1475 else {
1476 tcp->u_rval = err;
1477 u_error = 0;
1478 }
1479 } else {
1480 if (r10) {
1481 tcp->u_rval = -1;
1482 u_error = r8;
1483 } else {
1484 tcp->u_rval = r8;
1485 u_error = 0;
1486 }
1487 }
1488#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001489#ifdef MIPS
1490 if (a3) {
1491 tcp->u_rval = -1;
1492 u_error = r2;
1493 } else {
1494 tcp->u_rval = r2;
1495 u_error = 0;
1496 }
1497#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001499 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500 tcp->u_rval = -1;
1501 u_error = -result;
1502 }
1503 else {
1504 tcp->u_rval = result;
1505 u_error = 0;
1506 }
1507#else /* !POWERPC */
1508#ifdef M68K
1509 if (d0 && (unsigned) -d0 < nerrnos) {
1510 tcp->u_rval = -1;
1511 u_error = -d0;
1512 }
1513 else {
1514 tcp->u_rval = d0;
1515 u_error = 0;
1516 }
1517#else /* !M68K */
1518#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001519 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001521 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001522 }
1523 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001524 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525 u_error = 0;
1526 }
1527#else /* !ARM */
1528#ifdef ALPHA
1529 if (a3) {
1530 tcp->u_rval = -1;
1531 u_error = r0;
1532 }
1533 else {
1534 tcp->u_rval = r0;
1535 u_error = 0;
1536 }
1537#else /* !ALPHA */
1538#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001539 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001541 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001542 }
1543 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001544 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545 u_error = 0;
1546 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001547#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001548#ifdef SPARC64
1549 if (regs.r_tstate & 0x1100000000UL) {
1550 tcp->u_rval = -1;
1551 u_error = regs.r_o0;
1552 }
1553 else {
1554 tcp->u_rval = regs.r_o0;
1555 u_error = 0;
1556 }
1557#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001558#ifdef HPPA
1559 if (r28 && (unsigned) -r28 < nerrnos) {
1560 tcp->u_rval = -1;
1561 u_error = -r28;
1562 }
1563 else {
1564 tcp->u_rval = r28;
1565 u_error = 0;
1566 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001567#else
1568#ifdef SH
1569 /* interpret R0 as return value or error number */
1570 if (r0 && (unsigned) -r0 < nerrnos) {
1571 tcp->u_rval = -1;
1572 u_error = -r0;
1573 }
1574 else {
1575 tcp->u_rval = r0;
1576 u_error = 0;
1577 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001578#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001579#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001580 /* interpret result as return value or error number */
1581 if (r9 && (unsigned) -r9 < nerrnos) {
1582 tcp->u_rval = -1;
1583 u_error = -r9;
1584 }
1585 else {
1586 tcp->u_rval = r9;
1587 u_error = 0;
1588 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001589#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001590#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001591#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001593#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594#endif /* ALPHA */
1595#endif /* ARM */
1596#endif /* M68K */
1597#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001598#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001599#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001600#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001602#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603#endif /* LINUX */
1604#ifdef SUNOS4
1605 /* get error code from user struct */
1606 if (upeek(pid, uoff(u_error), &u_error) < 0)
1607 return -1;
1608 u_error >>= 24; /* u_error is a char */
1609
1610 /* get system call return value */
1611 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1612 return -1;
1613#endif /* SUNOS4 */
1614#ifdef SVR4
1615#ifdef SPARC
1616 /* Judicious guessing goes a long way. */
1617 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1618 tcp->u_rval = -1;
1619 u_error = tcp->status.pr_reg[R_O0];
1620 }
1621 else {
1622 tcp->u_rval = tcp->status.pr_reg[R_O0];
1623 u_error = 0;
1624 }
1625#endif /* SPARC */
1626#ifdef I386
1627 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001628 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001630 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 }
1632 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001633 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001634#ifdef HAVE_LONG_LONG
1635 tcp->u_lrval =
1636 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1637 tcp->status.PR_REG[EAX];
1638#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 u_error = 0;
1640 }
1641#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001642#ifdef X86_64
1643 /* Wanna know how to kill an hour single-stepping? */
1644 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1645 tcp->u_rval = -1;
1646 u_error = tcp->status.PR_REG[RAX];
1647 }
1648 else {
1649 tcp->u_rval = tcp->status.PR_REG[RAX];
1650 u_error = 0;
1651 }
1652#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653#ifdef MIPS
1654 if (tcp->status.pr_reg[CTX_A3]) {
1655 tcp->u_rval = -1;
1656 u_error = tcp->status.pr_reg[CTX_V0];
1657 }
1658 else {
1659 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1660 u_error = 0;
1661 }
1662#endif /* MIPS */
1663#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001664#ifdef FREEBSD
1665 if (regs.r_eflags & PSL_C) {
1666 tcp->u_rval = -1;
1667 u_error = regs.r_eax;
1668 } else {
1669 tcp->u_rval = regs.r_eax;
1670 tcp->u_lrval =
1671 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1672 u_error = 0;
1673 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001674#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001675 tcp->u_error = u_error;
1676 return 1;
1677}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678
Roland McGrathb69f81b2002-12-21 23:25:18 +00001679int
1680force_result(tcp, error, rval)
1681 struct tcb *tcp;
1682 int error;
1683 long rval;
1684{
1685#ifdef LINUX
1686#if defined(S390) || defined(S390X)
1687 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001688 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1689 return -1;
1690#else /* !S390 && !S390X */
1691#ifdef I386
1692 eax = error ? -error : rval;
1693 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1694 return -1;
1695#else /* !I386 */
1696#ifdef X86_64
1697 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001698 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001699 return -1;
1700#else
1701#ifdef IA64
1702 if (ia32) {
1703 r8 = error ? -error : rval;
1704 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1705 return -1;
1706 }
1707 else {
1708 if (error) {
1709 r8 = error;
1710 r10 = -1;
1711 }
1712 else {
1713 r8 = rval;
1714 r10 = 0;
1715 }
1716 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1717 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1718 return -1;
1719 }
1720#else /* !IA64 */
1721#ifdef MIPS
1722 if (error) {
1723 r2 = error;
1724 a3 = -1;
1725 }
1726 else {
1727 r2 = rval;
1728 a3 = 0;
1729 }
1730 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1731 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1732 return -1;
1733#else
1734#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001735 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001736 return -1;
1737 if (error) {
1738 flags |= SO_MASK;
1739 result = error;
1740 }
1741 else {
1742 flags &= ~SO_MASK;
1743 result = rval;
1744 }
Roland McGratheb285352003-01-14 09:59:00 +00001745 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1746 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001747 return -1;
1748#else /* !POWERPC */
1749#ifdef M68K
1750 d0 = error ? -error : rval;
1751 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1752 return -1;
1753#else /* !M68K */
1754#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001755 regs.ARM_r0 = error ? -error : rval;
1756 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001757 return -1;
1758#else /* !ARM */
1759#ifdef ALPHA
1760 if (error) {
1761 a3 = -1;
1762 r0 = error;
1763 }
1764 else {
1765 a3 = 0;
1766 r0 = rval;
1767 }
1768 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1769 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1770 return -1;
1771#else /* !ALPHA */
1772#ifdef SPARC
1773 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1774 return -1;
1775 if (error) {
1776 regs.r_psr |= PSR_C;
1777 regs.r_o0 = error;
1778 }
1779 else {
1780 regs.r_psr &= ~PSR_C;
1781 regs.r_o0 = rval;
1782 }
1783 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1784 return -1;
1785#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001786#ifdef SPARC64
1787 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1788 return -1;
1789 if (error) {
1790 regs.r_tstate |= 0x1100000000UL;
1791 regs.r_o0 = error;
1792 }
1793 else {
1794 regs.r_tstate &= ~0x1100000000UL;
1795 regs.r_o0 = rval;
1796 }
1797 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1798 return -1;
1799#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001800#ifdef HPPA
1801 r28 = error ? -error : rval;
1802 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1803 return -1;
1804#else
1805#ifdef SH
1806 r0 = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1808 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001809#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001810#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001811 r9 = error ? -error : rval;
1812 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1813 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001814#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001815#endif /* SH */
1816#endif /* HPPA */
1817#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001818#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001819#endif /* ALPHA */
1820#endif /* ARM */
1821#endif /* M68K */
1822#endif /* POWERPC */
1823#endif /* MIPS */
1824#endif /* IA64 */
1825#endif /* X86_64 */
1826#endif /* I386 */
1827#endif /* S390 || S390X */
1828#endif /* LINUX */
1829#ifdef SUNOS4
1830 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1831 error << 24) < 0 ||
1832 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1833 return -1;
1834#endif /* SUNOS4 */
1835#ifdef SVR4
1836 /* XXX no clue */
1837 return -1;
1838#endif /* SVR4 */
1839#ifdef FREEBSD
1840 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1841 perror("pread");
1842 return -1;
1843 }
1844 if (error) {
1845 regs.r_eflags |= PSL_C;
1846 regs.r_eax = error;
1847 }
1848 else {
1849 regs.r_eflags &= ~PSL_C;
1850 regs.r_eax = rval;
1851 }
1852 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1853 perror("pwrite");
1854 return -1;
1855 }
1856#endif /* FREEBSD */
1857
1858 /* All branches reach here on success (only). */
1859 tcp->u_error = error;
1860 tcp->u_rval = rval;
1861 return 0;
1862}
1863
Roland McGratha4d48532005-06-08 20:45:28 +00001864static int
1865syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001866struct tcb *tcp;
1867{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001868#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001869 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001870#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001872#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001873 {
1874 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001875 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1876 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001877 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001878 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001879 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001880 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001881 return -1;
1882 }
1883 }
1884#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001885 {
1886 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001887 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1888 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001889 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001890 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001892 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1893 * for scno somewhere above here!
1894 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1896 return -1;
1897 }
1898 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001899#elif defined (IA64)
1900 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001901 if (!ia32) {
1902 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1903 /* be backwards compatible with kernel < 2.4.4... */
1904# ifndef PT_RBS_END
1905# define PT_RBS_END PT_AR_BSP
1906# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001907
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001908 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001909 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001910 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1911 return -1;
1912
1913 sof = (cfm >> 0) & 0x7f;
1914 sol = (cfm >> 7) & 0x7f;
1915 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1916
1917 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1918 && sysent[tcp->scno].nargs != -1)
1919 tcp->u_nargs = sysent[tcp->scno].nargs;
1920 else
1921 tcp->u_nargs = MAX_ARGS;
1922 for (i = 0; i < tcp->u_nargs; ++i) {
1923 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1924 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1925 return -1;
1926 }
1927 } else {
1928 int i;
1929
1930 if (/* EBX = out0 */
1931 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1932 /* ECX = out1 */
1933 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1934 /* EDX = out2 */
1935 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1936 /* ESI = out3 */
1937 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1938 /* EDI = out4 */
1939 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1940 /* EBP = out5 */
1941 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1942 return -1;
1943
1944 for (i = 0; i < 6; ++i)
1945 /* truncate away IVE sign-extension */
1946 tcp->u_arg[i] &= 0xffffffff;
1947
1948 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1949 && sysent[tcp->scno].nargs != -1)
1950 tcp->u_nargs = sysent[tcp->scno].nargs;
1951 else
1952 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001953 }
1954 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001955#elif defined (MIPS)
1956 {
1957 long sp;
1958 int i, nargs;
1959
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001960 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1961 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001962 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001963 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001964 if(nargs > 4) {
1965 if(upeek(pid, REG_SP, &sp) < 0)
1966 return -1;
1967 for(i = 0; i < 4; i++) {
1968 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1969 return -1;
1970 }
1971 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1972 (char *)(tcp->u_arg + 4));
1973 } else {
1974 for(i = 0; i < nargs; i++) {
1975 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1976 return -1;
1977 }
1978 }
1979 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00001981#ifndef PT_ORIG_R3
1982#define PT_ORIG_R3 34
1983#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001984 {
1985 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001986 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1987 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001988 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001989 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001990 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00001991 if (upeek(pid, (i==0) ?
1992 (sizeof(unsigned long)*PT_ORIG_R3) :
1993 ((i+PT_R3)*sizeof(unsigned long)),
1994 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 return -1;
1996 }
1997 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001998#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001999 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002000 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002001
2002 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2003 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002004 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002005 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002007 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002008 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002009#elif defined (HPPA)
2010 {
2011 int i;
2012
2013 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2014 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002015 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002016 tcp->u_nargs = MAX_ARGS;
2017 for (i = 0; i < tcp->u_nargs; i++) {
2018 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2019 return -1;
2020 }
2021 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002022#elif defined(ARM)
2023 {
2024 int i;
2025
2026 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2027 tcp->u_nargs = sysent[tcp->scno].nargs;
2028 else
2029 tcp->u_nargs = MAX_ARGS;
2030 for (i = 0; i < tcp->u_nargs; i++)
2031 tcp->u_arg[i] = regs.uregs[i];
2032 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002033#elif defined(SH)
2034 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002035 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002036 static int syscall_regs[] = {
2037 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2038 REG_REG0, REG_REG0+1, REG_REG0+2
2039 };
2040
2041 tcp->u_nargs = sysent[tcp->scno].nargs;
2042 for (i = 0; i < tcp->u_nargs; i++) {
2043 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2044 return -1;
2045 }
2046 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002047#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002048 {
2049 int i;
2050 /* Registers used by SH5 Linux system calls for parameters */
2051 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2052
2053 /*
2054 * TODO: should also check that the number of arguments encoded
2055 * in the trap number matches the number strace expects.
2056 */
2057 /*
2058 assert(sysent[tcp->scno].nargs <
2059 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2060 */
2061
2062 tcp->u_nargs = sysent[tcp->scno].nargs;
2063 for (i = 0; i < tcp->u_nargs; i++) {
2064 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2065 return -1;
2066 }
2067 }
2068
Michal Ludvig0e035502002-09-23 15:41:01 +00002069#elif defined(X86_64)
2070 {
2071 int i;
2072 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2073 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002074 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002075 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002076
Michal Ludvig0e035502002-09-23 15:41:01 +00002077 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2078 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002079 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002080 tcp->u_nargs = MAX_ARGS;
2081 for (i = 0; i < tcp->u_nargs; i++) {
2082 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2083 return -1;
2084 }
2085 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002086#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002087 {
2088 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002089 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2090 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002091 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002092 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093 for (i = 0; i < tcp->u_nargs; i++) {
2094 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2095 return -1;
2096 }
2097 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002098#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099#endif /* LINUX */
2100#ifdef SUNOS4
2101 {
2102 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002103 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2104 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002105 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002106 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002107 for (i = 0; i < tcp->u_nargs; i++) {
2108 struct user *u;
2109
2110 if (upeek(pid, uoff(u_arg[0]) +
2111 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2112 return -1;
2113 }
2114 }
2115#endif /* SUNOS4 */
2116#ifdef SVR4
2117#ifdef MIPS
2118 /*
2119 * SGI is broken: even though it has pr_sysarg, it doesn't
2120 * set them on system call entry. Get a clue.
2121 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002122 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 tcp->u_nargs = sysent[tcp->scno].nargs;
2124 else
2125 tcp->u_nargs = tcp->status.pr_nsysarg;
2126 if (tcp->u_nargs > 4) {
2127 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2128 4*sizeof(tcp->u_arg[0]));
2129 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2130 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2131 }
2132 else {
2133 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2134 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2135 }
John Hughes25299712001-03-06 10:10:06 +00002136#elif UNIXWARE >= 2
2137 /*
2138 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2139 */
2140 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2141 tcp->u_nargs = sysent[tcp->scno].nargs;
2142 else
2143 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2144 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2145 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2146#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002147 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002148 tcp->u_nargs = sysent[tcp->scno].nargs;
2149 else
2150 tcp->u_nargs = tcp->status.pr_nsysarg;
2151 {
2152 int i;
2153 for (i = 0; i < tcp->u_nargs; i++)
2154 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2155 }
John Hughes25299712001-03-06 10:10:06 +00002156#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002157 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 tcp->u_nargs = sysent[tcp->scno].nargs;
2159 else
2160 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002161 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002162 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002163#else
2164 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002166#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002167#ifdef FREEBSD
2168 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2169 sysent[tcp->scno].nargs > tcp->status.val)
2170 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002171 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002172 tcp->u_nargs = tcp->status.val;
2173 if (tcp->u_nargs < 0)
2174 tcp->u_nargs = 0;
2175 if (tcp->u_nargs > MAX_ARGS)
2176 tcp->u_nargs = MAX_ARGS;
2177 switch(regs.r_eax) {
2178 case SYS___syscall:
2179 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2180 regs.r_esp + sizeof(int) + sizeof(quad_t));
2181 break;
2182 case SYS_syscall:
2183 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2184 regs.r_esp + 2 * sizeof(int));
2185 break;
2186 default:
2187 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2188 regs.r_esp + sizeof(int));
2189 break;
2190 }
2191#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002192 return 1;
2193}
2194
2195int
2196trace_syscall(tcp)
2197struct tcb *tcp;
2198{
2199 int sys_res;
2200 struct timeval tv;
2201 int res;
2202
2203 /* Measure the exit time as early as possible to avoid errors. */
2204 if (dtime && (tcp->flags & TCB_INSYSCALL))
2205 gettimeofday(&tv, NULL);
2206
2207 res = get_scno(tcp);
2208 if (res != 1)
2209 return res;
2210
2211 res = syscall_fixup(tcp);
2212 if (res != 1)
2213 return res;
2214
2215 if (tcp->flags & TCB_INSYSCALL) {
2216 long u_error;
2217 res = get_error(tcp);
2218 if (res != 1)
2219 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002220
2221 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002222 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2223 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002224 tcp->flags &= ~TCB_INSYSCALL;
2225 return 0;
2226 }
2227
2228 if (tcp->flags & TCB_REPRINT) {
2229 printleader(tcp);
2230 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002231 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002232 tprintf("syscall_%lu", tcp->scno);
2233 else
2234 tprintf("%s", sysent[tcp->scno].sys_name);
2235 tprintf(" resumed> ");
2236 }
2237
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Roland McGrathe10e62a2004-09-04 04:20:43 +00002239 if (counts == NULL) {
2240 counts = calloc(sizeof *counts, nsyscalls);
2241 if (counts == NULL) {
2242 fprintf(stderr, "\
2243strace: out of memory for call counts\n");
2244 exit(1);
2245 }
2246 }
2247
2248 counts[tcp->scno].calls++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002249 if (tcp->u_error)
Roland McGrathe10e62a2004-09-04 04:20:43 +00002250 counts[tcp->scno].errors++;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002251 tv_sub(&tv, &tv, &tcp->etime);
2252#ifdef LINUX
2253 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002254 static struct timeval one_tick;
2255 if (one_tick.tv_usec == 0) {
2256 /* Initialize it. */
2257 struct itimerval it;
2258 memset(&it, 0, sizeof it);
2259 it.it_interval.tv_usec = 1;
2260 setitimer(ITIMER_REAL, &it, NULL);
2261 getitimer(ITIMER_REAL, &it);
2262 one_tick = it.it_interval;
2263 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002264
2265 if (tv_nz(&tcp->dtime))
2266 tv = tcp->dtime;
2267 else if (tv_cmp(&tv, &one_tick) > 0) {
2268 if (tv_cmp(&shortest, &one_tick) < 0)
2269 tv = shortest;
2270 else
2271 tv = one_tick;
2272 }
2273 }
2274#endif /* LINUX */
2275 if (tv_cmp(&tv, &shortest) < 0)
2276 shortest = tv;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002277 tv_add(&counts[tcp->scno].time,
2278 &counts[tcp->scno].time, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002279 tcp->flags &= ~TCB_INSYSCALL;
2280 return 0;
2281 }
2282
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002283 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002284 || (qual_flags[tcp->scno] & QUAL_RAW))
2285 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002286 else {
2287 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002288 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002289 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002290 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002291 u_error = tcp->u_error;
2292 tprintf(") ");
2293 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2295 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002296 if (u_error)
2297 tprintf("= -1 (errno %ld)", u_error);
2298 else
2299 tprintf("= %#lx", tcp->u_rval);
2300 }
2301 else if (!(sys_res & RVAL_NONE) && u_error) {
2302 switch (u_error) {
2303#ifdef LINUX
2304 case ERESTARTSYS:
2305 tprintf("= ? ERESTARTSYS (To be restarted)");
2306 break;
2307 case ERESTARTNOINTR:
2308 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2309 break;
2310 case ERESTARTNOHAND:
2311 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2312 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002313 case ERESTART_RESTARTBLOCK:
2314 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2315 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002316#endif /* LINUX */
2317 default:
2318 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002319 if (u_error < 0)
2320 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002322 tprintf("%s (%s)", errnoent[u_error],
2323 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002325 tprintf("ERRNO_%ld (%s)", u_error,
2326 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002327 break;
2328 }
2329 }
2330 else {
2331 if (sys_res & RVAL_NONE)
2332 tprintf("= ?");
2333 else {
2334 switch (sys_res & RVAL_MASK) {
2335 case RVAL_HEX:
2336 tprintf("= %#lx", tcp->u_rval);
2337 break;
2338 case RVAL_OCTAL:
2339 tprintf("= %#lo", tcp->u_rval);
2340 break;
2341 case RVAL_UDECIMAL:
2342 tprintf("= %lu", tcp->u_rval);
2343 break;
2344 case RVAL_DECIMAL:
2345 tprintf("= %ld", tcp->u_rval);
2346 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002347#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348 case RVAL_LHEX:
2349 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002350 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 case RVAL_LOCTAL:
2352 tprintf("= %#llo", tcp->u_lrval);
2353 break;
2354 case RVAL_LUDECIMAL:
2355 tprintf("= %llu", tcp->u_lrval);
2356 break;
2357 case RVAL_LDECIMAL:
2358 tprintf("= %lld", tcp->u_lrval);
2359 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002360#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002361 default:
2362 fprintf(stderr,
2363 "invalid rval format\n");
2364 break;
2365 }
2366 }
2367 if ((sys_res & RVAL_STR) && tcp->auxstr)
2368 tprintf(" (%s)", tcp->auxstr);
2369 }
2370 if (dtime) {
2371 tv_sub(&tv, &tv, &tcp->etime);
2372 tprintf(" <%ld.%06ld>",
2373 (long) tv.tv_sec, (long) tv.tv_usec);
2374 }
2375 printtrailer(tcp);
2376
2377 dumpio(tcp);
2378 if (fflush(tcp->outf) == EOF)
2379 return -1;
2380 tcp->flags &= ~TCB_INSYSCALL;
2381 return 0;
2382 }
2383
2384 /* Entering system call */
2385 res = syscall_enter(tcp);
2386 if (res != 1)
2387 return res;
2388
Roland McGrath17352792005-06-07 23:21:26 +00002389 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002390#ifdef LINUX
Roland McGrath17352792005-06-07 23:21:26 +00002391#if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002392 case SYS_socketcall:
2393 decode_subcall(tcp, SYS_socket_subcall,
2394 SYS_socket_nsubcalls, deref_style);
2395 break;
2396 case SYS_ipc:
2397 decode_subcall(tcp, SYS_ipc_subcall,
2398 SYS_ipc_nsubcalls, shift_style);
2399 break;
Roland McGrath17352792005-06-07 23:21:26 +00002400#endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002401#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002402 case SYS_socketcall:
2403 sparc_socket_decode (tcp);
2404 break;
2405#endif
2406#endif /* LINUX */
2407#ifdef SVR4
2408#ifdef SYS_pgrpsys_subcall
2409 case SYS_pgrpsys:
2410 decode_subcall(tcp, SYS_pgrpsys_subcall,
2411 SYS_pgrpsys_nsubcalls, shift_style);
2412 break;
2413#endif /* SYS_pgrpsys_subcall */
2414#ifdef SYS_sigcall_subcall
2415 case SYS_sigcall:
2416 decode_subcall(tcp, SYS_sigcall_subcall,
2417 SYS_sigcall_nsubcalls, mask_style);
2418 break;
2419#endif /* SYS_sigcall_subcall */
2420 case SYS_msgsys:
2421 decode_subcall(tcp, SYS_msgsys_subcall,
2422 SYS_msgsys_nsubcalls, shift_style);
2423 break;
2424 case SYS_shmsys:
2425 decode_subcall(tcp, SYS_shmsys_subcall,
2426 SYS_shmsys_nsubcalls, shift_style);
2427 break;
2428 case SYS_semsys:
2429 decode_subcall(tcp, SYS_semsys_subcall,
2430 SYS_semsys_nsubcalls, shift_style);
2431 break;
2432#if 0 /* broken */
2433 case SYS_utssys:
2434 decode_subcall(tcp, SYS_utssys_subcall,
2435 SYS_utssys_nsubcalls, shift_style);
2436 break;
2437#endif
2438 case SYS_sysfs:
2439 decode_subcall(tcp, SYS_sysfs_subcall,
2440 SYS_sysfs_nsubcalls, shift_style);
2441 break;
2442 case SYS_spcall:
2443 decode_subcall(tcp, SYS_spcall_subcall,
2444 SYS_spcall_nsubcalls, shift_style);
2445 break;
2446#ifdef SYS_context_subcall
2447 case SYS_context:
2448 decode_subcall(tcp, SYS_context_subcall,
2449 SYS_context_nsubcalls, shift_style);
2450 break;
2451#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002452#ifdef SYS_door_subcall
2453 case SYS_door:
2454 decode_subcall(tcp, SYS_door_subcall,
2455 SYS_door_nsubcalls, door_style);
2456 break;
2457#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002458#ifdef SYS_kaio_subcall
2459 case SYS_kaio:
2460 decode_subcall(tcp, SYS_kaio_subcall,
2461 SYS_kaio_nsubcalls, shift_style);
2462 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002463#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002464#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002465#ifdef FREEBSD
2466 case SYS_msgsys:
2467 case SYS_shmsys:
2468 case SYS_semsys:
2469 decode_subcall(tcp, 0, 0, table_style);
2470 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002471#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002472#ifdef SUNOS4
2473 case SYS_semsys:
2474 decode_subcall(tcp, SYS_semsys_subcall,
2475 SYS_semsys_nsubcalls, shift_style);
2476 break;
2477 case SYS_msgsys:
2478 decode_subcall(tcp, SYS_msgsys_subcall,
2479 SYS_msgsys_nsubcalls, shift_style);
2480 break;
2481 case SYS_shmsys:
2482 decode_subcall(tcp, SYS_shmsys_subcall,
2483 SYS_shmsys_nsubcalls, shift_style);
2484 break;
2485#endif
2486 }
2487
2488 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002489 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002490 tcp->flags |= TCB_INSYSCALL;
2491 return 0;
2492 }
2493
2494 if (cflag) {
2495 gettimeofday(&tcp->etime, NULL);
2496 tcp->flags |= TCB_INSYSCALL;
2497 return 0;
2498 }
2499
2500 printleader(tcp);
2501 tcp->flags &= ~TCB_REPRINT;
2502 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002503 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002504 tprintf("syscall_%lu(", tcp->scno);
2505 else
2506 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002507 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002508 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2509 sys_res = printargs(tcp);
2510 else
2511 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2512 if (fflush(tcp->outf) == EOF)
2513 return -1;
2514 tcp->flags |= TCB_INSYSCALL;
2515 /* Measure the entrance time as late as possible to avoid errors. */
2516 if (dtime)
2517 gettimeofday(&tcp->etime, NULL);
2518 return sys_res;
2519}
2520
2521int
2522printargs(tcp)
2523struct tcb *tcp;
2524{
2525 if (entering(tcp)) {
2526 int i;
2527
2528 for (i = 0; i < tcp->u_nargs; i++)
2529 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2530 }
2531 return 0;
2532}
2533
2534long
2535getrval2(tcp)
2536struct tcb *tcp;
2537{
2538 long val = -1;
2539
2540#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002541#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002542 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2544 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002545 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002546#elif defined(SH)
2547 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2548 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002549#elif defined(IA64)
2550 if (upeek(tcp->pid, PT_R9, &val) < 0)
2551 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002552#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002553#endif /* LINUX */
2554
2555#ifdef SUNOS4
2556 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2557 return -1;
2558#endif /* SUNOS4 */
2559
2560#ifdef SVR4
2561#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002562 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002563#endif /* SPARC */
2564#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002565 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002567#ifdef X86_64
2568 val = tcp->status.PR_REG[RDX];
2569#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002571 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002572#endif /* MIPS */
2573#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002574#ifdef FREEBSD
2575 struct reg regs;
2576 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2577 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002578#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002579 return val;
2580}
2581
2582/*
2583 * Apparently, indirect system calls have already be converted by ptrace(2),
2584 * so if you see "indir" this program has gone astray.
2585 */
2586int
2587sys_indir(tcp)
2588struct tcb *tcp;
2589{
2590 int i, scno, nargs;
2591
2592 if (entering(tcp)) {
2593 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2594 fprintf(stderr, "Bogus syscall: %u\n", scno);
2595 return 0;
2596 }
2597 nargs = sysent[scno].nargs;
2598 tprintf("%s", sysent[scno].sys_name);
2599 for (i = 0; i < nargs; i++)
2600 tprintf(", %#lx", tcp->u_arg[i+1]);
2601 }
2602 return 0;
2603}
2604
2605static int
2606time_cmp(a, b)
2607void *a;
2608void *b;
2609{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002610 return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002611}
2612
2613static int
2614syscall_cmp(a, b)
2615void *a;
2616void *b;
2617{
2618 return strcmp(sysent[*((int *) a)].sys_name,
2619 sysent[*((int *) b)].sys_name);
2620}
2621
2622static int
2623count_cmp(a, b)
2624void *a;
2625void *b;
2626{
Roland McGrathe10e62a2004-09-04 04:20:43 +00002627 int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002628
2629 return (m < n) ? 1 : (m > n) ? -1 : 0;
2630}
2631
2632static int (*sortfun)();
2633static struct timeval overhead = { -1, -1 };
2634
2635void
2636set_sortby(sortby)
2637char *sortby;
2638{
2639 if (strcmp(sortby, "time") == 0)
2640 sortfun = time_cmp;
2641 else if (strcmp(sortby, "calls") == 0)
2642 sortfun = count_cmp;
2643 else if (strcmp(sortby, "name") == 0)
2644 sortfun = syscall_cmp;
2645 else if (strcmp(sortby, "nothing") == 0)
2646 sortfun = NULL;
2647 else {
2648 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2649 exit(1);
2650 }
2651}
2652
2653void set_overhead(n)
2654int n;
2655{
2656 overhead.tv_sec = n / 1000000;
2657 overhead.tv_usec = n % 1000000;
2658}
2659
2660void
2661call_summary(outf)
2662FILE *outf;
2663{
2664 int i, j;
2665 int call_cum, error_cum;
2666 struct timeval tv_cum, dtv;
2667 double percent;
2668 char *dashes = "-------------------------";
2669 char error_str[16];
2670
Roland McGrathe10e62a2004-09-04 04:20:43 +00002671 int *sorted_count = malloc(nsyscalls * sizeof(int));
2672
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002673 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2674 if (overhead.tv_sec == -1) {
2675 tv_mul(&overhead, &shortest, 8);
2676 tv_div(&overhead, &overhead, 10);
2677 }
2678 for (i = 0; i < nsyscalls; i++) {
2679 sorted_count[i] = i;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002680 if (counts == NULL || counts[i].calls == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681 continue;
Roland McGrathe10e62a2004-09-04 04:20:43 +00002682 tv_mul(&dtv, &overhead, counts[i].calls);
2683 tv_sub(&counts[i].time, &counts[i].time, &dtv);
2684 call_cum += counts[i].calls;
2685 error_cum += counts[i].errors;
2686 tv_add(&tv_cum, &tv_cum, &counts[i].time);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 }
Roland McGrathb77d0932005-02-02 04:42:25 +00002688 if (counts && sortfun)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002689 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2690 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2691 "% time", "seconds", "usecs/call",
2692 "calls", "errors", "syscall");
2693 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2694 dashes, dashes, dashes, dashes, dashes, dashes);
Roland McGrathe10e62a2004-09-04 04:20:43 +00002695 if (counts) {
2696 for (i = 0; i < nsyscalls; i++) {
2697 j = sorted_count[i];
2698 if (counts[j].calls == 0)
2699 continue;
2700 tv_div(&dtv, &counts[j].time, counts[j].calls);
2701 if (counts[j].errors)
2702 sprintf(error_str, "%d", counts[j].errors);
2703 else
2704 error_str[0] = '\0';
2705 percent = (100.0 * tv_float(&counts[j].time)
2706 / tv_float(&tv_cum));
2707 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2708 percent, (long) counts[j].time.tv_sec,
2709 (long) counts[j].time.tv_usec,
2710 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2711 counts[j].calls,
2712 error_str, sysent[j].sys_name);
2713 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714 }
Roland McGrathe10e62a2004-09-04 04:20:43 +00002715 free(sorted_count);
2716
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002717 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2718 dashes, dashes, dashes, dashes, dashes, dashes);
2719 if (error_cum)
2720 sprintf(error_str, "%d", error_cum);
2721 else
2722 error_str[0] = '\0';
2723 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2724 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2725 call_cum, error_str, "total");
Roland McGrathe10e62a2004-09-04 04:20:43 +00002726
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002727}