return;
}
-static void
-dumpio(struct tcb *tcp)
-{
- if (syserror(tcp))
- return;
- if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
- return;
- if (tcp->scno < 0 || tcp->scno >= nsyscalls)
- return;
- if (sysent[tcp->scno].sys_func == printargs)
- return;
- if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
- if (sysent[tcp->scno].sys_func == sys_read ||
- sysent[tcp->scno].sys_func == sys_pread ||
- sysent[tcp->scno].sys_func == sys_pread64 ||
- sysent[tcp->scno].sys_func == sys_recv ||
- sysent[tcp->scno].sys_func == sys_recvfrom)
- dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
- else if (sysent[tcp->scno].sys_func == sys_readv)
- dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
- return;
- }
- if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
- if (sysent[tcp->scno].sys_func == sys_write ||
- sysent[tcp->scno].sys_func == sys_pwrite ||
- sysent[tcp->scno].sys_func == sys_pwrite64 ||
- sysent[tcp->scno].sys_func == sys_send ||
- sysent[tcp->scno].sys_func == sys_sendto)
- dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
- else if (sysent[tcp->scno].sys_func == sys_writev)
- dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
- return;
- }
-}
-
#ifndef FREEBSD
enum subcall_style { shift_style, deref_style, mask_style, door_style };
#else /* FREEBSD */
}
#endif
-struct tcb *tcp_last = NULL;
-
-static int
-internal_syscall(struct tcb *tcp)
+int
+printargs(struct tcb *tcp)
{
- /*
- * We must always trace a few critical system calls in order to
- * correctly support following forks in the presence of tracing
- * qualifiers.
- */
- int (*func)();
+ if (entering(tcp)) {
+ int i;
- if (tcp->scno < 0 || tcp->scno >= nsyscalls)
- return 0;
+ for (i = 0; i < tcp->u_nargs; i++)
+ tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
+ }
+ return 0;
+}
- func = sysent[tcp->scno].sys_func;
+long
+getrval2(struct tcb *tcp)
+{
+ long val = -1;
- if ( sys_fork == func
-#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
- || sys_vfork == func
-#endif
#ifdef LINUX
- || sys_clone == func
-#endif
-#if UNIXWARE > 2
- || sys_rfork == func
+#if defined (SPARC) || defined (SPARC64)
+ struct pt_regs regs;
+ if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0)
+ return -1;
+ val = regs.u_regs[U_REG_O1];
+#elif defined(SH)
+ if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
+ return -1;
+#elif defined(IA64)
+ if (upeek(tcp, PT_R9, &val) < 0)
+ return -1;
#endif
- )
- return internal_fork(tcp);
+#endif /* LINUX */
-#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
- if ( sys_execve == func
-# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
- || sys_execv == func
-# endif
-# if UNIXWARE > 2
- || sys_rexecve == func
-# endif
- )
- return internal_exec(tcp);
+#ifdef SUNOS4
+ if (upeek(tcp, uoff(u_rval2), &val) < 0)
+ return -1;
+#endif /* SUNOS4 */
+
+#ifdef SVR4
+#ifdef SPARC
+ val = tcp->status.PR_REG[R_O1];
+#endif /* SPARC */
+#ifdef I386
+ val = tcp->status.PR_REG[EDX];
+#endif /* I386 */
+#ifdef X86_64
+ val = tcp->status.PR_REG[RDX];
+#endif /* X86_64 */
+#ifdef MIPS
+ val = tcp->status.PR_REG[CTX_V1];
+#endif /* MIPS */
+#endif /* SVR4 */
+
+#ifdef FREEBSD
+ struct reg regs;
+ pread(tcp->pfd_reg, ®s, sizeof(regs), 0);
+ val = regs.r_edx;
#endif
+ return val;
+}
+
+#ifdef SUNOS4
+/*
+ * Apparently, indirect system calls have already be converted by ptrace(2),
+ * so if you see "indir" this program has gone astray.
+ */
+int
+sys_indir(struct tcb *tcp)
+{
+ int i, scno, nargs;
+
+ if (entering(tcp)) {
+ scno = tcp->u_arg[0];
+ if (scno > nsyscalls) {
+ fprintf(stderr, "Bogus syscall: %u\n", scno);
+ return 0;
+ }
+ nargs = sysent[scno].nargs;
+ tprintf("%s", sysent[scno].sys_name);
+ for (i = 0; i < nargs; i++)
+ tprintf(", %#lx", tcp->u_arg[i+1]);
+ }
+ return 0;
+}
+#endif /* SUNOS4 */
+int
+is_restart_error(struct tcb *tcp)
+{
+#ifdef LINUX
+ if (!syserror(tcp))
+ return 0;
+ switch (tcp->u_error) {
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ case ERESTARTNOHAND:
+ case ERESTART_RESTARTBLOCK:
+ return 1;
+ default:
+ break;
+ }
+#endif /* LINUX */
return 0;
}
+struct tcb *tcp_last = NULL;
#ifdef LINUX
# if defined (I386)
return 1;
}
-/* Returns:
- * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
- * 1: ok, continue in trace_syscall().
- * other: error, trace_syscall() should print error indicator
- * ("????" etc) and bail out.
- */
-static int
-get_syscall_result(struct tcb *tcp)
-{
-#ifdef LINUX
-# if defined(S390) || defined(S390X)
-# elif defined (POWERPC)
-# elif defined(AVR32)
- /* Read complete register set in one go. */
- if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, ®s) < 0)
- return -1;
-# elif defined(BFIN)
-# elif defined (I386)
- if (upeek(tcp, 4*EAX, &eax) < 0)
- return -1;
-# elif defined (X86_64)
- if (upeek(tcp, 8*RAX, &rax) < 0)
- return -1;
-# elif defined(IA64)
-# define IA64_PSR_IS ((long)1 << 34)
- if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
- ia32 = (psr & IA64_PSR_IS) != 0;
- if (upeek(tcp, PT_R8, &r8) < 0)
- return -1;
- if (upeek(tcp, PT_R10, &r10) < 0)
- return -1;
-# elif defined (ARM)
- /* Read complete register set in one go. */
- if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1)
- return -1;
-# elif defined (M68K)
-# elif defined (LINUX_MIPSN32)
- unsigned long long regs[38];
-
- if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) ®s) < 0)
- return -1;
- a3 = regs[REG_A3];
- r2 = regs[REG_V0];
-# elif defined (MIPS)
- if (upeek(tcp, REG_A3, &a3) < 0)
- return -1;
- if (upeek(tcp, REG_V0, &r2) < 0)
- return -1;
-# elif defined (ALPHA)
- if (upeek(tcp, REG_A3, &a3) < 0)
- return -1;
- if (upeek(tcp, REG_R0, &r0) < 0)
- return -1;
-# elif defined (SPARC) || defined (SPARC64)
- /* Everything we need is in the current register set. */
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0)
- return -1;
-# elif defined(HPPA)
-# elif defined(SH)
-# elif defined(SH64)
-# elif defined(CRISV10) || defined(CRISV32)
-# elif defined(TILE)
-# elif defined(MICROBLAZE)
-# endif
-#endif /* LINUX */
-
-#ifdef SUNOS4
-#elif defined(SH)
- /* new syscall ABI returns result in R0 */
- if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
- return -1;
-#elif defined(SH64)
- /* ABI defines result returned in r9 */
- if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
- return -1;
-#endif
-
-#ifdef USE_PROCFS
-# ifndef HAVE_PR_SYSCALL
-# ifdef FREEBSD
- if (pread(tcp->pfd_reg, ®s, sizeof(regs), 0) < 0) {
- perror("pread");
- return -1;
- }
-# endif /* FREEBSD */
-# endif /* !HAVE_PR_SYSCALL */
-#endif /* USE_PROCFS */
-
- return 1;
-}
-
long
known_scno(struct tcb *tcp)
{
return 1;
}
-#ifdef LINUX
-/*
- * Check the syscall return value register value for whether it is
- * a negated errno code indicating an error, or a success return value.
- */
-static inline int
-is_negated_errno(unsigned long int val)
+static int
+internal_syscall(struct tcb *tcp)
{
- unsigned long int max = -(long int) nerrnos;
-# if SUPPORTED_PERSONALITIES > 1
- if (personality_wordsize[current_personality] < sizeof(val)) {
- val = (unsigned int) val;
- max = (unsigned int) max;
- }
+ /*
+ * We must always trace a few critical system calls in order to
+ * correctly support following forks in the presence of tracing
+ * qualifiers.
+ */
+ int (*func)();
+
+ if (tcp->scno < 0 || tcp->scno >= nsyscalls)
+ return 0;
+
+ func = sysent[tcp->scno].sys_func;
+
+ if ( sys_fork == func
+#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
+ || sys_vfork == func
+#endif
+#ifdef LINUX
+ || sys_clone == func
+#endif
+#if UNIXWARE > 2
+ || sys_rfork == func
+#endif
+ )
+ return internal_fork(tcp);
+
+#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
+ if ( sys_execve == func
+# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
+ || sys_execv == func
# endif
- return val > max;
-}
+# if UNIXWARE > 2
+ || sys_rexecve == func
+# endif
+ )
+ return internal_exec(tcp);
#endif
+ return 0;
+}
+
static int
-get_error(struct tcb *tcp)
+syscall_enter(struct tcb *tcp)
{
- int u_error = 0;
#ifdef LINUX
- int check_errno = 1;
- if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
- sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
- check_errno = 0;
- }
+ int i, nargs;
+
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ nargs = tcp->u_nargs = MAX_ARGS;
+
# if defined(S390) || defined(S390X)
- if (check_errno && is_negated_errno(gpr2)) {
- tcp->u_rval = -1;
- u_error = -gpr2;
- }
- else {
- tcp->u_rval = gpr2;
- u_error = 0;
- }
-# elif defined(I386)
- if (check_errno && is_negated_errno(eax)) {
- tcp->u_rval = -1;
- u_error = -eax;
- }
- else {
- tcp->u_rval = eax;
- u_error = 0;
- }
-# elif defined(X86_64)
- if (check_errno && is_negated_errno(rax)) {
- tcp->u_rval = -1;
- u_error = -rax;
- }
- else {
- tcp->u_rval = rax;
- u_error = 0;
- }
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
+ return -1;
+# elif defined(ALPHA)
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(IA64)
- if (ia32) {
- int err;
+ if (!ia32) {
+ unsigned long *out0, cfm, sof, sol;
+ long rbs_end;
+ /* be backwards compatible with kernel < 2.4.4... */
+# ifndef PT_RBS_END
+# define PT_RBS_END PT_AR_BSP
+# endif
- err = (int)r8;
- if (check_errno && is_negated_errno(err)) {
- tcp->u_rval = -1;
- u_error = -err;
- }
- else {
- tcp->u_rval = err;
- u_error = 0;
+ if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
+ return -1;
+ if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
+ return -1;
+
+ sof = (cfm >> 0) & 0x7f;
+ sol = (cfm >> 7) & 0x7f;
+ out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
+
+ for (i = 0; i < nargs; ++i) {
+ if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
+ sizeof(long), (char *) &tcp->u_arg[i]) < 0)
+ return -1;
}
} else {
- if (check_errno && r10) {
- tcp->u_rval = -1;
- u_error = r8;
- } else {
- tcp->u_rval = r8;
- u_error = 0;
+ static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
+ PT_R9 /* ECX = out1 */,
+ PT_R10 /* EDX = out2 */,
+ PT_R14 /* ESI = out3 */,
+ PT_R15 /* EDI = out4 */,
+ PT_R13 /* EBP = out5 */};
+
+ for (i = 0; i < nargs; ++i) {
+ if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
+ return -1;
+ /* truncate away IVE sign-extension */
+ tcp->u_arg[i] &= 0xffffffff;
}
}
+# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
+ /* N32 and N64 both use up to six registers. */
+ unsigned long long regs[38];
+
+ if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) ®s) < 0)
+ return -1;
+
+ for (i = 0; i < nargs; ++i) {
+ tcp->u_arg[i] = regs[REG_A0 + i];
+# if defined(LINUX_MIPSN32)
+ tcp->ext_arg[i] = regs[REG_A0 + i];
+# endif
+ }
# elif defined(MIPS)
- if (check_errno && a3) {
- tcp->u_rval = -1;
- u_error = r2;
+ if (nargs > 4) {
+ long sp;
+
+ if (upeek(tcp, REG_SP, &sp) < 0)
+ return -1;
+ for (i = 0; i < 4; ++i)
+ if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
+ return -1;
+ umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
+ (char *)(tcp->u_arg + 4));
} else {
- tcp->u_rval = r2;
- u_error = 0;
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
+ return -1;
}
# elif defined(POWERPC)
- if (check_errno && is_negated_errno(result)) {
- tcp->u_rval = -1;
- u_error = -result;
- }
- else {
- tcp->u_rval = result;
- u_error = 0;
- }
-# elif defined(M68K)
- if (check_errno && is_negated_errno(d0)) {
- tcp->u_rval = -1;
- u_error = -d0;
- }
- else {
- tcp->u_rval = d0;
- u_error = 0;
+# ifndef PT_ORIG_R3
+# define PT_ORIG_R3 34
+# endif
+ for (i = 0; i < nargs; ++i) {
+ if (upeek(tcp, (i==0) ?
+ (sizeof(unsigned long) * PT_ORIG_R3) :
+ ((i+PT_R3) * sizeof(unsigned long)),
+ &tcp->u_arg[i]) < 0)
+ return -1;
}
+# elif defined(SPARC) || defined(SPARC64)
+ for (i = 0; i < nargs; ++i)
+ tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
+# elif defined(HPPA)
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(ARM)
- if (check_errno && is_negated_errno(regs.ARM_r0)) {
- tcp->u_rval = -1;
- u_error = -regs.ARM_r0;
- }
- else {
- tcp->u_rval = regs.ARM_r0;
- u_error = 0;
- }
+ for (i = 0; i < nargs; ++i)
+ tcp->u_arg[i] = regs.uregs[i];
# elif defined(AVR32)
- if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
- tcp->u_rval = -1;
- u_error = -regs.r12;
- }
- else {
- tcp->u_rval = regs.r12;
- u_error = 0;
- }
+ static const unsigned long *argregp[MAX_ARGS] = { ®s.r12,
+ ®s.r11,
+ ®s.r10,
+ ®s.r9,
+ ®s.r5,
+ ®s.r3 };
+ for (i = 0; i < nargs; ++i)
+ tcp->u_arg[i] = *argregp[i];
# elif defined(BFIN)
- if (check_errno && is_negated_errno(r0)) {
- tcp->u_rval = -1;
- u_error = -r0;
- } else {
- tcp->u_rval = r0;
- u_error = 0;
- }
-# elif defined(ALPHA)
- if (check_errno && a3) {
- tcp->u_rval = -1;
- u_error = r0;
- }
- else {
- tcp->u_rval = r0;
- u_error = 0;
- }
-# elif defined(SPARC)
- if (check_errno && regs.psr & PSR_C) {
- tcp->u_rval = -1;
- u_error = regs.u_regs[U_REG_O0];
- }
- else {
- tcp->u_rval = regs.u_regs[U_REG_O0];
- u_error = 0;
- }
-# elif defined(SPARC64)
- if (check_errno && regs.tstate & 0x1100000000UL) {
- tcp->u_rval = -1;
- u_error = regs.u_regs[U_REG_O0];
- }
- else {
- tcp->u_rval = regs.u_regs[U_REG_O0];
- u_error = 0;
- }
-# elif defined(HPPA)
- if (check_errno && is_negated_errno(r28)) {
- tcp->u_rval = -1;
- u_error = -r28;
- }
- else {
- tcp->u_rval = r28;
- u_error = 0;
- }
+ static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
+
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(SH)
- /* interpret R0 as return value or error number */
- if (check_errno && is_negated_errno(r0)) {
- tcp->u_rval = -1;
- u_error = -r0;
- }
- else {
- tcp->u_rval = r0;
- u_error = 0;
- }
+ static const int syscall_regs[MAX_ARGS] = {
+ 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
+ 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
+ };
+
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(SH64)
- /* interpret result as return value or error number */
- if (check_errno && is_negated_errno(r9)) {
- tcp->u_rval = -1;
- u_error = -r9;
- }
- else {
- tcp->u_rval = r9;
- u_error = 0;
- }
+ int i;
+ /* Registers used by SH5 Linux system calls for parameters */
+ static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
+
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
+ return -1;
+# elif defined(X86_64)
+ static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
+ { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
+ { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
+ };
+
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
+ return -1;
+# elif defined(MICROBLAZE)
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(CRISV10) || defined(CRISV32)
- if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
- tcp->u_rval = -1;
- u_error = -r10;
- }
- else {
- tcp->u_rval = r10;
- u_error = 0;
- }
+ static const int crisregs[MAX_ARGS] = {
+ 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
+ 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
+ };
+
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
+ return -1;
# elif defined(TILE)
- long rval;
- /* interpret result as return value or error number */
- if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
- return -1;
- if (check_errno && rval < 0 && rval > -nerrnos) {
- tcp->u_rval = -1;
- u_error = -rval;
- }
- else {
- tcp->u_rval = rval;
- u_error = 0;
- }
-# elif defined(MICROBLAZE)
- /* interpret result as return value or error number */
- if (check_errno && is_negated_errno(r3)) {
- tcp->u_rval = -1;
- u_error = -r3;
- }
- else {
- tcp->u_rval = r3;
- u_error = 0;
- }
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
+ return -1;
+# elif defined(M68K)
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
+ return -1;
+# else /* Other architecture (like i386) (32bits specific) */
+ for (i = 0; i < nargs; ++i)
+ if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
+ return -1;
# endif
#endif /* LINUX */
#ifdef SUNOS4
- /* get error code from user struct */
- if (upeek(tcp, uoff(u_error), &u_error) < 0)
- return -1;
- u_error >>= 24; /* u_error is a char */
+ int i, nargs;
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ nargs = tcp->u_nargs = MAX_ARGS;
+ for (i = 0; i < nargs; i++) {
+ struct user *u;
- /* get system call return value */
- if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
- return -1;
+ if (upeek(tcp, uoff(u_arg[0]) +
+ (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
+ return -1;
+ }
#endif /* SUNOS4 */
#ifdef SVR4
-# ifdef SPARC
- /* Judicious guessing goes a long way. */
- if (tcp->status.pr_reg[R_PSR] & 0x100000) {
- tcp->u_rval = -1;
- u_error = tcp->status.pr_reg[R_O0];
- }
- else {
- tcp->u_rval = tcp->status.pr_reg[R_O0];
- u_error = 0;
- }
-# endif /* SPARC */
-# ifdef I386
- /* Wanna know how to kill an hour single-stepping? */
- if (tcp->status.PR_REG[EFL] & 0x1) {
- tcp->u_rval = -1;
- u_error = tcp->status.PR_REG[EAX];
- }
- else {
- tcp->u_rval = tcp->status.PR_REG[EAX];
-# ifdef HAVE_LONG_LONG
- tcp->u_lrval =
- ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
- tcp->status.PR_REG[EAX];
-# endif
- u_error = 0;
- }
-# endif /* I386 */
-# ifdef X86_64
- /* Wanna know how to kill an hour single-stepping? */
- if (tcp->status.PR_REG[EFLAGS] & 0x1) {
- tcp->u_rval = -1;
- u_error = tcp->status.PR_REG[RAX];
- }
- else {
- tcp->u_rval = tcp->status.PR_REG[RAX];
- u_error = 0;
- }
-# endif /* X86_64 */
# ifdef MIPS
- if (tcp->status.pr_reg[CTX_A3]) {
- tcp->u_rval = -1;
- u_error = tcp->status.pr_reg[CTX_V0];
+ /*
+ * SGI is broken: even though it has pr_sysarg, it doesn't
+ * set them on system call entry. Get a clue.
+ */
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ tcp->u_nargs = tcp->status.pr_nsysarg;
+ if (tcp->u_nargs > 4) {
+ memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
+ 4 * sizeof(tcp->u_arg[0]));
+ umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
+ (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
}
else {
- tcp->u_rval = tcp->status.pr_reg[CTX_V0];
- u_error = 0;
+ memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
+ tcp->u_nargs * sizeof(tcp->u_arg[0]));
}
-# endif /* MIPS */
+# elif UNIXWARE >= 2
+ /*
+ * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
+ */
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
+ umoven(tcp, tcp->status.PR_REG[UESP] + 4,
+ tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
+# elif defined(HAVE_PR_SYSCALL)
+ int i;
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ tcp->u_nargs = tcp->status.pr_nsysarg;
+ for (i = 0; i < tcp->u_nargs; i++)
+ tcp->u_arg[i] = tcp->status.pr_sysarg[i];
+# elif defined(I386)
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ tcp->u_nargs = 5;
+ if (tcp->u_nargs > 0)
+ umoven(tcp, tcp->status.PR_REG[UESP] + 4,
+ tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
+# else
+ I DONT KNOW WHAT TO DO
+# endif
#endif /* SVR4 */
#ifdef FREEBSD
- if (regs.r_eflags & PSL_C) {
- tcp->u_rval = -1;
- u_error = regs.r_eax;
- } else {
- tcp->u_rval = regs.r_eax;
- tcp->u_lrval =
- ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
- u_error = 0;
- }
-#endif /* FREEBSD */
- tcp->u_error = u_error;
- return 1;
-}
-
-static int
-syscall_enter(struct tcb *tcp)
-{
-#ifdef LINUX
- int i, nargs;
-
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- nargs = tcp->u_nargs = MAX_ARGS;
-
-# if defined(S390) || defined(S390X)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(ALPHA)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(IA64)
- if (!ia32) {
- unsigned long *out0, cfm, sof, sol;
- long rbs_end;
- /* be backwards compatible with kernel < 2.4.4... */
-# ifndef PT_RBS_END
-# define PT_RBS_END PT_AR_BSP
-# endif
-
- if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
- return -1;
- if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
- return -1;
-
- sof = (cfm >> 0) & 0x7f;
- sol = (cfm >> 7) & 0x7f;
- out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
-
- for (i = 0; i < nargs; ++i) {
- if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
- sizeof(long), (char *) &tcp->u_arg[i]) < 0)
- return -1;
- }
- } else {
- static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
- PT_R9 /* ECX = out1 */,
- PT_R10 /* EDX = out2 */,
- PT_R14 /* ESI = out3 */,
- PT_R15 /* EDI = out4 */,
- PT_R13 /* EBP = out5 */};
-
- for (i = 0; i < nargs; ++i) {
- if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
- return -1;
- /* truncate away IVE sign-extension */
- tcp->u_arg[i] &= 0xffffffff;
- }
- }
-# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
- /* N32 and N64 both use up to six registers. */
- unsigned long long regs[38];
-
- if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) ®s) < 0)
- return -1;
-
- for (i = 0; i < nargs; ++i) {
- tcp->u_arg[i] = regs[REG_A0 + i];
-# if defined(LINUX_MIPSN32)
- tcp->ext_arg[i] = regs[REG_A0 + i];
-# endif
- }
-# elif defined(MIPS)
- if (nargs > 4) {
- long sp;
-
- if (upeek(tcp, REG_SP, &sp) < 0)
- return -1;
- for (i = 0; i < 4; ++i)
- if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
- return -1;
- umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
- (char *)(tcp->u_arg + 4));
- } else {
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
- return -1;
- }
-# elif defined(POWERPC)
-# ifndef PT_ORIG_R3
-# define PT_ORIG_R3 34
-# endif
- for (i = 0; i < nargs; ++i) {
- if (upeek(tcp, (i==0) ?
- (sizeof(unsigned long) * PT_ORIG_R3) :
- ((i+PT_R3) * sizeof(unsigned long)),
- &tcp->u_arg[i]) < 0)
- return -1;
- }
-# elif defined(SPARC) || defined(SPARC64)
- for (i = 0; i < nargs; ++i)
- tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
-# elif defined(HPPA)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(ARM)
- for (i = 0; i < nargs; ++i)
- tcp->u_arg[i] = regs.uregs[i];
-# elif defined(AVR32)
- static const unsigned long *argregp[MAX_ARGS] = { ®s.r12,
- ®s.r11,
- ®s.r10,
- ®s.r9,
- ®s.r5,
- ®s.r3 };
- for (i = 0; i < nargs; ++i)
- tcp->u_arg[i] = *argregp[i];
-# elif defined(BFIN)
- static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
-
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(SH)
- static const int syscall_regs[MAX_ARGS] = {
- 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
- 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
- };
-
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(SH64)
- int i;
- /* Registers used by SH5 Linux system calls for parameters */
- static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
-
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(X86_64)
- static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
- { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
- { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
- };
-
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(MICROBLAZE)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(CRISV10) || defined(CRISV32)
- static const int crisregs[MAX_ARGS] = {
- 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
- 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
- };
-
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(TILE)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
- return -1;
-# elif defined(M68K)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
- return -1;
-# else /* Other architecture (like i386) (32bits specific) */
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
- return -1;
-# endif
-#endif /* LINUX */
-#ifdef SUNOS4
- int i, nargs;
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- nargs = tcp->u_nargs = MAX_ARGS;
- for (i = 0; i < nargs; i++) {
- struct user *u;
-
- if (upeek(tcp, uoff(u_arg[0]) +
- (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
- return -1;
- }
-#endif /* SUNOS4 */
-#ifdef SVR4
-# ifdef MIPS
- /*
- * SGI is broken: even though it has pr_sysarg, it doesn't
- * set them on system call entry. Get a clue.
- */
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- tcp->u_nargs = tcp->status.pr_nsysarg;
- if (tcp->u_nargs > 4) {
- memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
- 4 * sizeof(tcp->u_arg[0]));
- umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
- (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
- }
- else {
- memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
- tcp->u_nargs * sizeof(tcp->u_arg[0]));
- }
-# elif UNIXWARE >= 2
- /*
- * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
- */
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
- umoven(tcp, tcp->status.PR_REG[UESP] + 4,
- tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
-# elif defined(HAVE_PR_SYSCALL)
- int i;
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- tcp->u_nargs = tcp->status.pr_nsysarg;
- for (i = 0; i < tcp->u_nargs; i++)
- tcp->u_arg[i] = tcp->status.pr_sysarg[i];
-# elif defined(I386)
- if (tcp->scno >= 0 && tcp->scno < nsyscalls)
- tcp->u_nargs = sysent[tcp->scno].nargs;
- else
- tcp->u_nargs = 5;
- if (tcp->u_nargs > 0)
- umoven(tcp, tcp->status.PR_REG[UESP] + 4,
- tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
-# else
- I DONT KNOW WHAT TO DO
-# endif
-#endif /* SVR4 */
-#ifdef FREEBSD
- if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
- sysent[tcp->scno].nargs > tcp->status.val)
- tcp->u_nargs = sysent[tcp->scno].nargs;
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+ sysent[tcp->scno].nargs > tcp->status.val)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
else
tcp->u_nargs = tcp->status.val;
if (tcp->u_nargs < 0)
#endif
#endif /* SVR4 */
#ifdef FREEBSD
- case SYS_msgsys:
- case SYS_shmsys:
- case SYS_semsys:
- decode_subcall(tcp, 0, 0, table_style);
- break;
-#endif
-#ifdef SUNOS4
- case SYS_semsys:
- decode_subcall(tcp, SYS_semsys_subcall,
- SYS_semsys_nsubcalls, shift_style);
- break;
- case SYS_msgsys:
- decode_subcall(tcp, SYS_msgsys_subcall,
- SYS_msgsys_nsubcalls, shift_style);
- break;
- case SYS_shmsys:
- decode_subcall(tcp, SYS_shmsys_subcall,
- SYS_shmsys_nsubcalls, shift_style);
- break;
-#endif
+ case SYS_msgsys:
+ case SYS_shmsys:
+ case SYS_semsys:
+ decode_subcall(tcp, 0, 0, table_style);
+ break;
+#endif
+#ifdef SUNOS4
+ case SYS_semsys:
+ decode_subcall(tcp, SYS_semsys_subcall,
+ SYS_semsys_nsubcalls, shift_style);
+ break;
+ case SYS_msgsys:
+ decode_subcall(tcp, SYS_msgsys_subcall,
+ SYS_msgsys_nsubcalls, shift_style);
+ break;
+ case SYS_shmsys:
+ decode_subcall(tcp, SYS_shmsys_subcall,
+ SYS_shmsys_nsubcalls, shift_style);
+ break;
+#endif
+ }
+
+ internal_syscall(tcp);
+
+ if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
+ !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
+ (tracing_paths && !pathtrace_match(tcp))) {
+ tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
+ return 0;
+ }
+
+ tcp->flags &= ~TCB_FILTERED;
+
+ if (cflag == CFLAG_ONLY_STATS) {
+ res = 0;
+ goto ret;
+ }
+
+ printleader(tcp);
+ tcp->flags &= ~TCB_REPRINT;
+ tcp_last = tcp;
+ if (tcp->scno >= nsyscalls || tcp->scno < 0)
+ tprintf("syscall_%lu(", tcp->scno);
+ else
+ tprintf("%s(", sysent[tcp->scno].sys_name);
+ if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
+ ((qual_flags[tcp->scno] & QUAL_RAW) &&
+ sysent[tcp->scno].sys_func != sys_exit))
+ res = printargs(tcp);
+ else
+ res = (*sysent[tcp->scno].sys_func)(tcp);
+
+ if (fflush(tcp->outf) == EOF)
+ return -1;
+ ret:
+ tcp->flags |= TCB_INSYSCALL;
+ /* Measure the entrance time as late as possible to avoid errors. */
+ if (dtime || cflag)
+ gettimeofday(&tcp->etime, NULL);
+ return res;
+}
+
+/* Returns:
+ * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
+ * 1: ok, continue in trace_syscall().
+ * other: error, trace_syscall() should print error indicator
+ * ("????" etc) and bail out.
+ */
+static int
+get_syscall_result(struct tcb *tcp)
+{
+#ifdef LINUX
+# if defined(S390) || defined(S390X)
+# elif defined (POWERPC)
+# elif defined(AVR32)
+ /* Read complete register set in one go. */
+ if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, ®s) < 0)
+ return -1;
+# elif defined(BFIN)
+# elif defined (I386)
+ if (upeek(tcp, 4*EAX, &eax) < 0)
+ return -1;
+# elif defined (X86_64)
+ if (upeek(tcp, 8*RAX, &rax) < 0)
+ return -1;
+# elif defined(IA64)
+# define IA64_PSR_IS ((long)1 << 34)
+ if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
+ ia32 = (psr & IA64_PSR_IS) != 0;
+ if (upeek(tcp, PT_R8, &r8) < 0)
+ return -1;
+ if (upeek(tcp, PT_R10, &r10) < 0)
+ return -1;
+# elif defined (ARM)
+ /* Read complete register set in one go. */
+ if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1)
+ return -1;
+# elif defined (M68K)
+# elif defined (LINUX_MIPSN32)
+ unsigned long long regs[38];
+
+ if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) ®s) < 0)
+ return -1;
+ a3 = regs[REG_A3];
+ r2 = regs[REG_V0];
+# elif defined (MIPS)
+ if (upeek(tcp, REG_A3, &a3) < 0)
+ return -1;
+ if (upeek(tcp, REG_V0, &r2) < 0)
+ return -1;
+# elif defined (ALPHA)
+ if (upeek(tcp, REG_A3, &a3) < 0)
+ return -1;
+ if (upeek(tcp, REG_R0, &r0) < 0)
+ return -1;
+# elif defined (SPARC) || defined (SPARC64)
+ /* Everything we need is in the current register set. */
+ if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0)
+ return -1;
+# elif defined(HPPA)
+# elif defined(SH)
+# elif defined(SH64)
+# elif defined(CRISV10) || defined(CRISV32)
+# elif defined(TILE)
+# elif defined(MICROBLAZE)
+# endif
+#endif /* LINUX */
+
+#ifdef SUNOS4
+#elif defined(SH)
+ /* new syscall ABI returns result in R0 */
+ if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
+ return -1;
+#elif defined(SH64)
+ /* ABI defines result returned in r9 */
+ if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
+ return -1;
+#endif
+
+#ifdef USE_PROCFS
+# ifndef HAVE_PR_SYSCALL
+# ifdef FREEBSD
+ if (pread(tcp->pfd_reg, ®s, sizeof(regs), 0) < 0) {
+ perror("pread");
+ return -1;
+ }
+# endif /* FREEBSD */
+# endif /* !HAVE_PR_SYSCALL */
+#endif /* USE_PROCFS */
+
+ return 1;
+}
+
+#ifdef LINUX
+/*
+ * Check the syscall return value register value for whether it is
+ * a negated errno code indicating an error, or a success return value.
+ */
+static inline int
+is_negated_errno(unsigned long int val)
+{
+ unsigned long int max = -(long int) nerrnos;
+# if SUPPORTED_PERSONALITIES > 1
+ if (personality_wordsize[current_personality] < sizeof(val)) {
+ val = (unsigned int) val;
+ max = (unsigned int) max;
+ }
+# endif
+ return val > max;
+}
+#endif
+
+static int
+get_error(struct tcb *tcp)
+{
+ int u_error = 0;
+#ifdef LINUX
+ int check_errno = 1;
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+ sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
+ check_errno = 0;
+ }
+# if defined(S390) || defined(S390X)
+ if (check_errno && is_negated_errno(gpr2)) {
+ tcp->u_rval = -1;
+ u_error = -gpr2;
+ }
+ else {
+ tcp->u_rval = gpr2;
+ u_error = 0;
+ }
+# elif defined(I386)
+ if (check_errno && is_negated_errno(eax)) {
+ tcp->u_rval = -1;
+ u_error = -eax;
+ }
+ else {
+ tcp->u_rval = eax;
+ u_error = 0;
+ }
+# elif defined(X86_64)
+ if (check_errno && is_negated_errno(rax)) {
+ tcp->u_rval = -1;
+ u_error = -rax;
+ }
+ else {
+ tcp->u_rval = rax;
+ u_error = 0;
+ }
+# elif defined(IA64)
+ if (ia32) {
+ int err;
+
+ err = (int)r8;
+ if (check_errno && is_negated_errno(err)) {
+ tcp->u_rval = -1;
+ u_error = -err;
+ }
+ else {
+ tcp->u_rval = err;
+ u_error = 0;
+ }
+ } else {
+ if (check_errno && r10) {
+ tcp->u_rval = -1;
+ u_error = r8;
+ } else {
+ tcp->u_rval = r8;
+ u_error = 0;
+ }
+ }
+# elif defined(MIPS)
+ if (check_errno && a3) {
+ tcp->u_rval = -1;
+ u_error = r2;
+ } else {
+ tcp->u_rval = r2;
+ u_error = 0;
+ }
+# elif defined(POWERPC)
+ if (check_errno && is_negated_errno(result)) {
+ tcp->u_rval = -1;
+ u_error = -result;
+ }
+ else {
+ tcp->u_rval = result;
+ u_error = 0;
+ }
+# elif defined(M68K)
+ if (check_errno && is_negated_errno(d0)) {
+ tcp->u_rval = -1;
+ u_error = -d0;
+ }
+ else {
+ tcp->u_rval = d0;
+ u_error = 0;
+ }
+# elif defined(ARM)
+ if (check_errno && is_negated_errno(regs.ARM_r0)) {
+ tcp->u_rval = -1;
+ u_error = -regs.ARM_r0;
+ }
+ else {
+ tcp->u_rval = regs.ARM_r0;
+ u_error = 0;
+ }
+# elif defined(AVR32)
+ if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
+ tcp->u_rval = -1;
+ u_error = -regs.r12;
+ }
+ else {
+ tcp->u_rval = regs.r12;
+ u_error = 0;
+ }
+# elif defined(BFIN)
+ if (check_errno && is_negated_errno(r0)) {
+ tcp->u_rval = -1;
+ u_error = -r0;
+ } else {
+ tcp->u_rval = r0;
+ u_error = 0;
+ }
+# elif defined(ALPHA)
+ if (check_errno && a3) {
+ tcp->u_rval = -1;
+ u_error = r0;
+ }
+ else {
+ tcp->u_rval = r0;
+ u_error = 0;
+ }
+# elif defined(SPARC)
+ if (check_errno && regs.psr & PSR_C) {
+ tcp->u_rval = -1;
+ u_error = regs.u_regs[U_REG_O0];
+ }
+ else {
+ tcp->u_rval = regs.u_regs[U_REG_O0];
+ u_error = 0;
+ }
+# elif defined(SPARC64)
+ if (check_errno && regs.tstate & 0x1100000000UL) {
+ tcp->u_rval = -1;
+ u_error = regs.u_regs[U_REG_O0];
+ }
+ else {
+ tcp->u_rval = regs.u_regs[U_REG_O0];
+ u_error = 0;
+ }
+# elif defined(HPPA)
+ if (check_errno && is_negated_errno(r28)) {
+ tcp->u_rval = -1;
+ u_error = -r28;
+ }
+ else {
+ tcp->u_rval = r28;
+ u_error = 0;
+ }
+# elif defined(SH)
+ /* interpret R0 as return value or error number */
+ if (check_errno && is_negated_errno(r0)) {
+ tcp->u_rval = -1;
+ u_error = -r0;
+ }
+ else {
+ tcp->u_rval = r0;
+ u_error = 0;
+ }
+# elif defined(SH64)
+ /* interpret result as return value or error number */
+ if (check_errno && is_negated_errno(r9)) {
+ tcp->u_rval = -1;
+ u_error = -r9;
+ }
+ else {
+ tcp->u_rval = r9;
+ u_error = 0;
+ }
+# elif defined(CRISV10) || defined(CRISV32)
+ if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
+ tcp->u_rval = -1;
+ u_error = -r10;
+ }
+ else {
+ tcp->u_rval = r10;
+ u_error = 0;
+ }
+# elif defined(TILE)
+ long rval;
+ /* interpret result as return value or error number */
+ if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
+ return -1;
+ if (check_errno && rval < 0 && rval > -nerrnos) {
+ tcp->u_rval = -1;
+ u_error = -rval;
+ }
+ else {
+ tcp->u_rval = rval;
+ u_error = 0;
+ }
+# elif defined(MICROBLAZE)
+ /* interpret result as return value or error number */
+ if (check_errno && is_negated_errno(r3)) {
+ tcp->u_rval = -1;
+ u_error = -r3;
+ }
+ else {
+ tcp->u_rval = r3;
+ u_error = 0;
+ }
+# endif
+#endif /* LINUX */
+#ifdef SUNOS4
+ /* get error code from user struct */
+ if (upeek(tcp, uoff(u_error), &u_error) < 0)
+ return -1;
+ u_error >>= 24; /* u_error is a char */
+
+ /* get system call return value */
+ if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
+ return -1;
+#endif /* SUNOS4 */
+#ifdef SVR4
+# ifdef SPARC
+ /* Judicious guessing goes a long way. */
+ if (tcp->status.pr_reg[R_PSR] & 0x100000) {
+ tcp->u_rval = -1;
+ u_error = tcp->status.pr_reg[R_O0];
+ }
+ else {
+ tcp->u_rval = tcp->status.pr_reg[R_O0];
+ u_error = 0;
+ }
+# endif /* SPARC */
+# ifdef I386
+ /* Wanna know how to kill an hour single-stepping? */
+ if (tcp->status.PR_REG[EFL] & 0x1) {
+ tcp->u_rval = -1;
+ u_error = tcp->status.PR_REG[EAX];
+ }
+ else {
+ tcp->u_rval = tcp->status.PR_REG[EAX];
+# ifdef HAVE_LONG_LONG
+ tcp->u_lrval =
+ ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
+ tcp->status.PR_REG[EAX];
+# endif
+ u_error = 0;
+ }
+# endif /* I386 */
+# ifdef X86_64
+ /* Wanna know how to kill an hour single-stepping? */
+ if (tcp->status.PR_REG[EFLAGS] & 0x1) {
+ tcp->u_rval = -1;
+ u_error = tcp->status.PR_REG[RAX];
+ }
+ else {
+ tcp->u_rval = tcp->status.PR_REG[RAX];
+ u_error = 0;
+ }
+# endif /* X86_64 */
+# ifdef MIPS
+ if (tcp->status.pr_reg[CTX_A3]) {
+ tcp->u_rval = -1;
+ u_error = tcp->status.pr_reg[CTX_V0];
+ }
+ else {
+ tcp->u_rval = tcp->status.pr_reg[CTX_V0];
+ u_error = 0;
+ }
+# endif /* MIPS */
+#endif /* SVR4 */
+#ifdef FREEBSD
+ if (regs.r_eflags & PSL_C) {
+ tcp->u_rval = -1;
+ u_error = regs.r_eax;
+ } else {
+ tcp->u_rval = regs.r_eax;
+ tcp->u_lrval =
+ ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
+ u_error = 0;
}
+#endif /* FREEBSD */
+ tcp->u_error = u_error;
+ return 1;
+}
- internal_syscall(tcp);
-
- if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
- !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
- (tracing_paths && !pathtrace_match(tcp))) {
- tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
- return 0;
+static void
+dumpio(struct tcb *tcp)
+{
+ if (syserror(tcp))
+ return;
+ if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
+ return;
+ if (tcp->scno < 0 || tcp->scno >= nsyscalls)
+ return;
+ if (sysent[tcp->scno].sys_func == printargs)
+ return;
+ if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
+ if (sysent[tcp->scno].sys_func == sys_read ||
+ sysent[tcp->scno].sys_func == sys_pread ||
+ sysent[tcp->scno].sys_func == sys_pread64 ||
+ sysent[tcp->scno].sys_func == sys_recv ||
+ sysent[tcp->scno].sys_func == sys_recvfrom)
+ dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
+ else if (sysent[tcp->scno].sys_func == sys_readv)
+ dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+ return;
}
-
- tcp->flags &= ~TCB_FILTERED;
-
- if (cflag == CFLAG_ONLY_STATS) {
- res = 0;
- goto ret;
+ if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
+ if (sysent[tcp->scno].sys_func == sys_write ||
+ sysent[tcp->scno].sys_func == sys_pwrite ||
+ sysent[tcp->scno].sys_func == sys_pwrite64 ||
+ sysent[tcp->scno].sys_func == sys_send ||
+ sysent[tcp->scno].sys_func == sys_sendto)
+ dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
+ else if (sysent[tcp->scno].sys_func == sys_writev)
+ dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+ return;
}
-
- printleader(tcp);
- tcp->flags &= ~TCB_REPRINT;
- tcp_last = tcp;
- if (tcp->scno >= nsyscalls || tcp->scno < 0)
- tprintf("syscall_%lu(", tcp->scno);
- else
- tprintf("%s(", sysent[tcp->scno].sys_name);
- if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
- ((qual_flags[tcp->scno] & QUAL_RAW) &&
- sysent[tcp->scno].sys_func != sys_exit))
- res = printargs(tcp);
- else
- res = (*sysent[tcp->scno].sys_func)(tcp);
-
- if (fflush(tcp->outf) == EOF)
- return -1;
- ret:
- tcp->flags |= TCB_INSYSCALL;
- /* Measure the entrance time as late as possible to avoid errors. */
- if (dtime || cflag)
- gettimeofday(&tcp->etime, NULL);
- return res;
}
static int
return exiting(tcp) ?
trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
}
-
-int
-printargs(struct tcb *tcp)
-{
- if (entering(tcp)) {
- int i;
-
- for (i = 0; i < tcp->u_nargs; i++)
- tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
- }
- return 0;
-}
-
-long
-getrval2(struct tcb *tcp)
-{
- long val = -1;
-
-#ifdef LINUX
-#if defined (SPARC) || defined (SPARC64)
- struct pt_regs regs;
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0)
- return -1;
- val = regs.u_regs[U_REG_O1];
-#elif defined(SH)
- if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
- return -1;
-#elif defined(IA64)
- if (upeek(tcp, PT_R9, &val) < 0)
- return -1;
-#endif
-#endif /* LINUX */
-
-#ifdef SUNOS4
- if (upeek(tcp, uoff(u_rval2), &val) < 0)
- return -1;
-#endif /* SUNOS4 */
-
-#ifdef SVR4
-#ifdef SPARC
- val = tcp->status.PR_REG[R_O1];
-#endif /* SPARC */
-#ifdef I386
- val = tcp->status.PR_REG[EDX];
-#endif /* I386 */
-#ifdef X86_64
- val = tcp->status.PR_REG[RDX];
-#endif /* X86_64 */
-#ifdef MIPS
- val = tcp->status.PR_REG[CTX_V1];
-#endif /* MIPS */
-#endif /* SVR4 */
-
-#ifdef FREEBSD
- struct reg regs;
- pread(tcp->pfd_reg, ®s, sizeof(regs), 0);
- val = regs.r_edx;
-#endif
- return val;
-}
-
-#ifdef SUNOS4
-/*
- * Apparently, indirect system calls have already be converted by ptrace(2),
- * so if you see "indir" this program has gone astray.
- */
-int
-sys_indir(struct tcb *tcp)
-{
- int i, scno, nargs;
-
- if (entering(tcp)) {
- scno = tcp->u_arg[0];
- if (scno > nsyscalls) {
- fprintf(stderr, "Bogus syscall: %u\n", scno);
- return 0;
- }
- nargs = sysent[scno].nargs;
- tprintf("%s", sysent[scno].sys_name);
- for (i = 0; i < nargs; i++)
- tprintf(", %#lx", tcp->u_arg[i+1]);
- }
- return 0;
-}
-#endif /* SUNOS4 */
-
-int
-is_restart_error(struct tcb *tcp)
-{
-#ifdef LINUX
- if (!syserror(tcp))
- return 0;
- switch (tcp->u_error) {
- case ERESTARTSYS:
- case ERESTARTNOINTR:
- case ERESTARTNOHAND:
- case ERESTART_RESTARTBLOCK:
- return 1;
- default:
- break;
- }
-#endif /* LINUX */
- return 0;
-}