From a614692fb082294ae3d3c7f6c1ed26b355d6c4bf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 24 Aug 2011 18:07:22 +0200 Subject: [PATCH] Reorder functions in syscall.c. No code changes. Old order (basically "in no particular order"): dumpio decode_subcall internal_syscall get_scno get_syscall_result known_scno syscall_fixup is_negated_errno get_error syscall_enter trace_syscall_entering trace_syscall_exiting trace_syscall printargs getrval2 sys_indir is_restart_error New order: various utility functions: decode_subcall printargs getrval2 sys_indir is_restart_error syscall enter handling functions: get_scno known_scno syscall_fixup (also used in syscall exit code) internal_syscall (also used in syscall exit code) syscall_enter trace_syscall_entering syscall exit handling functions: get_syscall_result is_negated_errno get_error dumpio trace_syscall_exiting main syscall enter/exit function: trace_syscall * syscall.c: Reorder functions so that related ones are closer in the source. Signed-off-by: Denys Vlasenko --- syscall.c | 1637 ++++++++++++++++++++++++++--------------------------- 1 file changed, 818 insertions(+), 819 deletions(-) diff --git a/syscall.c b/syscall.c index 3951066d..ed104170 100644 --- a/syscall.c +++ b/syscall.c @@ -507,41 +507,6 @@ qualify(const char *s) 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 */ @@ -642,51 +607,111 @@ decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style s } #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) @@ -1198,97 +1223,6 @@ get_scno(struct tcb *tcp) 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) { @@ -1481,544 +1415,292 @@ syscall_fixup(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) @@ -2151,66 +1833,487 @@ trace_syscall_entering(struct tcb *tcp) #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 @@ -2390,107 +2493,3 @@ trace_syscall(struct tcb *tcp) 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; -} -- 2.40.0