/* Returns: * 0: "bail out". * 1: ok. * -1: error in one of ptrace ops. * * If not 0, call syscall_exiting_trace(tcp, res), where res is the return * value. Anyway, call syscall_exiting_finish(tcp) then. */ int syscall_exiting_decode(struct tcb *tcp, struct timeval *ptv) { /* Measure the exit time as early as possible to avoid errors. */ if ((Tflag || cflag) && !(filtered(tcp) || hide_log(tcp))) gettimeofday(ptv, NULL); #ifdef USE_LIBUNWIND if (stack_trace_enabled) { if (tcp->s_ent->sys_flags & STACKTRACE_INVALIDATE_CACHE) unwind_cache_invalidate(tcp); } #endif if (filtered(tcp) || hide_log(tcp)) return 0; get_regs(tcp->pid); #if SUPPORTED_PERSONALITIES > 1 update_personality(tcp, tcp->currpers); #endif return get_regs_error ? -1 : get_syscall_result(tcp); }
static int trace_syscall_exiting(struct tcb *tcp) { int sys_res; struct timeval tv; int res; long u_error; /* Measure the exit time as early as possible to avoid errors. */ if (Tflag || cflag) gettimeofday(&tv, NULL); #ifdef USE_LIBUNWIND if (stack_trace_enabled) { if (tcp->s_ent->sys_flags & STACKTRACE_INVALIDATE_CACHE) unwind_cache_invalidate(tcp); } #endif #if SUPPORTED_PERSONALITIES > 1 update_personality(tcp, tcp->currpers); #endif res = (get_regs_error ? -1 : get_syscall_result(tcp)); if (res == 1) { if (filtered(tcp) || hide_log_until_execve) goto ret; } if (cflag) { count_syscall(tcp, &tv); if (cflag == CFLAG_ONLY_STATS) { goto ret; } } /* If not in -ff mode, and printing_tcp != tcp, * then the log currently does not end with output * of _our syscall entry_, but with something else. * We need to say which syscall's return is this. * * Forced reprinting via TCB_REPRINT is used only by * "strace -ff -oLOG test/threaded_execve" corner case. * It's the only case when -ff mode needs reprinting. */ if ((followfork < 2 && printing_tcp != tcp) || (tcp->flags & TCB_REPRINT)) { tcp->flags &= ~TCB_REPRINT; printleader(tcp); if (tcp->qual_flg & UNDEFINED_SCNO) tprintf("<... %s resumed> ", undefined_scno_name(tcp)); else tprintf("<... %s resumed> ", tcp->s_ent->sys_name); } printing_tcp = tcp; tcp->s_prev_ent = NULL; if (res != 1) { /* There was error in one of prior ptrace ops */ tprints(") "); tabto(); tprints("= ? <unavailable>\n"); line_ended(); tcp->flags &= ~TCB_INSYSCALL; return res; } tcp->s_prev_ent = tcp->s_ent; sys_res = 0; if (tcp->qual_flg & QUAL_RAW) { /* sys_res = printargs(tcp); - but it's nop on sysexit */ } else { /* FIXME: not_failing_only (IOW, option -z) is broken: * failure of syscall is known only after syscall return. * Thus we end up with something like this on, say, ENOENT: * open("doesnt_exist", O_RDONLY <unfinished ...> * {next syscall decode} * whereas the intended result is that open(...) line * is not shown at all. */ if (not_failing_only && tcp->u_error) goto ret; /* ignore failed syscalls */ sys_res = tcp->s_ent->sys_func(tcp); } tprints(") "); tabto(); u_error = tcp->u_error; if (tcp->qual_flg & QUAL_RAW) { if (u_error) tprintf("= -1 (errno %ld)", u_error); else tprintf("= %#lx", tcp->u_rval); } else if (!(sys_res & RVAL_NONE) && u_error) { switch (u_error) { /* Blocked signals do not interrupt any syscalls. * In this case syscalls don't return ERESTARTfoo codes. * * Deadly signals set to SIG_DFL interrupt syscalls * and kill the process regardless of which of the codes below * is returned by the interrupted syscall. * In some cases, kernel forces a kernel-generated deadly * signal to be unblocked and set to SIG_DFL (and thus cause * death) if it is blocked or SIG_IGNed: for example, SIGSEGV * or SIGILL. (The alternative is to leave process spinning * forever on the faulty instruction - not useful). * * SIG_IGNed signals and non-deadly signals set to SIG_DFL * (for example, SIGCHLD, SIGWINCH) interrupt syscalls, * but kernel will always restart them. */ case ERESTARTSYS: /* Most common type of signal-interrupted syscall exit code. * The system call will be restarted with the same arguments * if SA_RESTART is set; otherwise, it will fail with EINTR. */ tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)"); break; case ERESTARTNOINTR: /* Rare. For example, fork() returns this if interrupted. * SA_RESTART is ignored (assumed set): the restart is unconditional. */ tprints("= ? ERESTARTNOINTR (To be restarted)"); break; case ERESTARTNOHAND: /* pause(), rt_sigsuspend() etc use this code. * SA_RESTART is ignored (assumed not set): * syscall won't restart (will return EINTR instead) * even after signal with SA_RESTART set. However, * after SIG_IGN or SIG_DFL signal it will restart * (thus the name "restart only if has no handler"). */ tprints("= ? ERESTARTNOHAND (To be restarted if no handler)"); break; case ERESTART_RESTARTBLOCK: /* Syscalls like nanosleep(), poll() which can't be * restarted with their original arguments use this * code. Kernel will execute restart_syscall() instead, * which changes arguments before restarting syscall. * SA_RESTART is ignored (assumed not set) similarly * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART * since restart data is saved in "restart block" * in task struct, and if signal handler uses a syscall * which in turn saves another such restart block, * old data is lost and restart becomes impossible) */ tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)"); break; default: if ((unsigned long) u_error < nerrnos && errnoent[u_error]) tprintf("= -1 %s (%s)", errnoent[u_error], strerror(u_error)); else tprintf("= -1 ERRNO_%lu (%s)", u_error, strerror(u_error)); break; } if ((sys_res & RVAL_STR) && tcp->auxstr) tprintf(" (%s)", tcp->auxstr); } else { if (sys_res & RVAL_NONE) tprints("= ?"); else { switch (sys_res & RVAL_MASK) { case RVAL_HEX: #if SUPPORTED_PERSONALITIES > 1 if (current_wordsize < sizeof(long)) tprintf("= %#x", (unsigned int) tcp->u_rval); else #endif tprintf("= %#lx", tcp->u_rval); break; case RVAL_OCTAL: tprintf("= %#lo", tcp->u_rval); break; case RVAL_UDECIMAL: tprintf("= %lu", tcp->u_rval); break; case RVAL_DECIMAL: tprintf("= %ld", tcp->u_rval); break; case RVAL_FD: if (show_fd_path) { tprints("= "); printfd(tcp, tcp->u_rval); } else tprintf("= %ld", tcp->u_rval); break; #if defined(LINUX_MIPSN32) || defined(X32) /* case RVAL_LHEX: tprintf("= %#llx", tcp->u_lrval); break; case RVAL_LOCTAL: tprintf("= %#llo", tcp->u_lrval); break; */ case RVAL_LUDECIMAL: tprintf("= %llu", tcp->u_lrval); break; /* case RVAL_LDECIMAL: tprintf("= %lld", tcp->u_lrval); break; */ #endif default: fprintf(stderr, "invalid rval format\n"); break; } } if ((sys_res & RVAL_STR) && tcp->auxstr) tprintf(" (%s)", tcp->auxstr); } if (Tflag) { tv_sub(&tv, &tv, &tcp->etime); tprintf(" <%ld.%06ld>", (long) tv.tv_sec, (long) tv.tv_usec); } tprints("\n"); dumpio(tcp); line_ended(); #ifdef USE_LIBUNWIND if (stack_trace_enabled) unwind_print_stacktrace(tcp); #endif ret: tcp->flags &= ~TCB_INSYSCALL; return 0; }
/* Return codes: 1 - ok, 0 - ignore, other - error. */ static int arch_get_scno(struct tcb *tcp) { kernel_ulong_t scno = 0; unsigned int currpers; #ifndef __X32_SYSCALL_BIT # define __X32_SYSCALL_BIT 0x40000000 #endif #if 1 /* * GETREGSET of NT_PRSTATUS tells us regset size, * which unambiguously detects i386. * * Linux kernel distinguishes x86-64 and x32 processes * solely by looking at __X32_SYSCALL_BIT: * arch/x86/include/asm/compat.h::is_x32_task(): * if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT) * return true; */ if (x86_io.iov_len == sizeof(i386_regs)) { scno = i386_regs.orig_eax; currpers = 1; } else { scno = x86_64_regs.orig_rax; currpers = 0; if (scno & __X32_SYSCALL_BIT) { /* * Syscall number -1 requires special treatment: * it might be a side effect of SECCOMP_RET_ERRNO * filtering that sets orig_rax to -1 * in some versions of linux kernel. * If that is the case, then * __X32_SYSCALL_BIT logic does not apply. */ if ((long long) x86_64_regs.orig_rax != -1) { scno -= __X32_SYSCALL_BIT; currpers = 2; } else { # ifdef X32 currpers = 2; # endif } } } #elif 0 /* * cs = 0x33 for long mode (native 64 bit and x32) * cs = 0x23 for compatibility mode (32 bit) * ds = 0x2b for x32 mode (x86-64 in 32 bit) */ scno = x86_64_regs.orig_rax; switch (x86_64_regs.cs) { case 0x23: currpers = 1; break; case 0x33: if (x86_64_regs.ds == 0x2b) { currpers = 2; scno &= ~__X32_SYSCALL_BIT; } else currpers = 0; break; default: error_msg("Unknown value CS=0x%08X while " "detecting personality of process PID=%d", (int)x86_64_regs.cs, tcp->pid); currpers = current_personality; break; } #elif 0 /* * This version analyzes the opcode of a syscall instruction. * (int 0x80 on i386 vs. syscall on x86-64) * It works, but is too complicated, and strictly speaking, unreliable. */ unsigned long call, rip = x86_64_regs.rip; /* sizeof(syscall) == sizeof(int 0x80) == 2 */ rip -= 2; errno = 0; call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0); if (errno) perror_msg("ptrace_peektext failed"); switch (call & 0xffff) { /* x86-64: syscall = 0x0f 0x05 */ case 0x050f: currpers = 0; break; /* i386: int 0x80 = 0xcd 0x80 */ case 0x80cd: currpers = 1; break; default: currpers = current_personality; error_msg("Unknown syscall opcode (0x%04X) while " "detecting personality of process PID=%d", (int)call, tcp->pid); break; } #endif #ifdef X32 /* * If we are built for a x32 system, then personality 0 is x32 * (not x86_64), and stracing of x86_64 apps is not supported. * Stracing of i386 apps is still supported. */ if (currpers == 0) { error_msg("syscall_%" PRI_klu "(...) in unsupported " "64-bit mode of process PID=%d", scno, tcp->pid); return 0; } currpers &= ~2; /* map 2,1 to 0,1 */ #endif /* X32 */ update_personality(tcp, currpers); tcp->scno = scno; return 1; }