int syscall_entering_trace(struct tcb *tcp, unsigned int *sig) { /* Restrain from fault injection while the trace executes strace code. */ if (hide_log(tcp)) { tcp->qual_flg &= ~QUAL_INJECT; } switch (tcp->s_ent->sen) { case SEN_execve: case SEN_execveat: #if defined SPARC || defined SPARC64 case SEN_execv: #endif tcp->flags &= ~TCB_HIDE_LOG; break; } if (!traced(tcp) || (tracing_paths && !pathtrace_match(tcp))) { tcp->flags |= TCB_FILTERED; return 0; } tcp->flags &= ~TCB_FILTERED; if (hide_log(tcp)) { return 0; } if (inject(tcp)) tamper_with_syscall_entering(tcp, sig); if (cflag == CFLAG_ONLY_STATS) { return 0; } #ifdef USE_LIBUNWIND if (stack_trace_enabled) { if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) unwind_capture_stacktrace(tcp); } #endif printleader(tcp); tprintf("%s(", tcp->s_ent->sys_name); int res = raw(tcp) ? printargs(tcp) : tcp->s_ent->sys_func(tcp); fflush(tcp->outf); return res; }
/* * Returns: * 0: "ignore this ptrace stop", bail out silently. * 1: ok, decoded; call * syscall_entering_finish(tcp, syscall_entering_trace(tcp, ...)). * other: error; call syscall_entering_finish(tcp, res), where res is the value * returned. */ int syscall_entering_decode(struct tcb *tcp) { int res = get_scno(tcp); if (res == 0) return res; int scno_good = res; if (res != 1 || (res = get_syscall_args(tcp)) != 1) { printleader(tcp); tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????"); /* * " <unavailable>" will be added later by the code which * detects ptrace errors. */ return res; } #ifdef LINUX_MIPSO32 if (SEN_syscall == tcp->s_ent->sen) decode_mips_subcall(tcp); #endif #if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall) switch (tcp->s_ent->sen) { # ifdef SYS_socket_subcall case SEN_socketcall: decode_socket_subcall(tcp); break; # endif # ifdef SYS_ipc_subcall case SEN_ipc: decode_ipc_subcall(tcp); break; # endif } #endif return 1; }
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; }
static int trace_syscall_entering(struct tcb *tcp) { int res, scno_good; scno_good = res = get_scno(tcp); if (res == 0) return res; if (res == 1) res = get_syscall_args(tcp); if (res != 1) { printleader(tcp); if (scno_good != 1) tprints("????" /* anti-trigraph gap */ "("); else if (tcp->qual_flg & UNDEFINED_SCNO) tprintf("%s(", undefined_scno_name(tcp)); else tprintf("%s(", tcp->s_ent->sys_name); /* * " <unavailable>" will be added later by the code which * detects ptrace errors. */ goto ret; } if ( sys_execve == tcp->s_ent->sys_func # if defined(SPARC) || defined(SPARC64) || sys_execv == tcp->s_ent->sys_func # endif ) { hide_log_until_execve = 0; } #if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall) while (1) { # ifdef SYS_socket_subcall if (tcp->s_ent->sys_func == sys_socketcall) { decode_socket_subcall(tcp); break; } # endif # ifdef SYS_ipc_subcall if (tcp->s_ent->sys_func == sys_ipc) { decode_ipc_subcall(tcp); break; } # endif break; } #endif if (!(tcp->qual_flg & QUAL_TRACE) || (tracing_paths && !pathtrace_match(tcp)) ) { tcp->flags |= TCB_INSYSCALL | TCB_FILTERED; return 0; } tcp->flags &= ~TCB_FILTERED; if (cflag == CFLAG_ONLY_STATS || hide_log_until_execve) { res = 0; goto ret; } #ifdef USE_LIBUNWIND if (stack_trace_enabled) { if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) unwind_capture_stacktrace(tcp); } #endif printleader(tcp); if (tcp->qual_flg & UNDEFINED_SCNO) tprintf("%s(", undefined_scno_name(tcp)); else tprintf("%s(", tcp->s_ent->sys_name); if ((tcp->qual_flg & QUAL_RAW) && tcp->s_ent->sys_func != sys_exit) res = printargs(tcp); else res = tcp->s_ent->sys_func(tcp); fflush(tcp->outf); ret: tcp->flags |= TCB_INSYSCALL; /* Measure the entrance time as late as possible to avoid errors. */ if (Tflag || cflag) gettimeofday(&tcp->etime, NULL); return res; }
int syscall_exiting_trace(struct tcb *tcp, struct timeval tv, int res) { if (syserror(tcp) && syscall_tampered(tcp)) tamper_with_syscall_exiting(tcp); if (cflag) { count_syscall(tcp, &tv); if (cflag == CFLAG_ONLY_STATS) { return 0; } } /* 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); 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(); return res; } tcp->s_prev_ent = tcp->s_ent; int sys_res = 0; if (raw(tcp)) { /* 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("does_not_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) return 0; /* ignore failed syscalls */ if (tcp->sys_func_rval & RVAL_DECODED) sys_res = tcp->sys_func_rval; else sys_res = tcp->s_ent->sys_func(tcp); } tprints(") "); tabto(); unsigned long u_error = tcp->u_error; if (raw(tcp)) { if (u_error) { tprintf("= -1 (errno %lu)", u_error); } else { tprintf("= %#" PRI_klx, tcp->u_rval); } if (syscall_tampered(tcp)) tprints(" (INJECTED)"); } else if (!(sys_res & RVAL_NONE) && u_error) { const char *u_error_str; 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: u_error_str = err_name(u_error); if (u_error_str) tprintf("= -1 %s (%s)", u_error_str, strerror(u_error)); else tprintf("= -1 %lu (%s)", u_error, strerror(u_error)); break; } if (syscall_tampered(tcp)) tprints(" (INJECTED)"); 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 ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(tcp->u_rval)) { tprintf("= %#x", (unsigned int) tcp->u_rval); } else #endif { tprintf("= %#" PRI_klx, tcp->u_rval); } break; case RVAL_OCTAL: tprints("= "); print_numeric_long_umask(tcp->u_rval); break; case RVAL_UDECIMAL: #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(tcp->u_rval)) { tprintf("= %u", (unsigned int) tcp->u_rval); } else #endif { tprintf("= %" PRI_klu, tcp->u_rval); } break; case RVAL_DECIMAL: tprintf("= %" PRI_kld, tcp->u_rval); break; case RVAL_FD: if (show_fd_path) { tprints("= "); printfd(tcp, tcp->u_rval); } else tprintf("= %" PRI_kld, tcp->u_rval); break; default: error_msg("invalid rval format"); break; } } if ((sys_res & RVAL_STR) && tcp->auxstr) tprintf(" (%s)", tcp->auxstr); if (syscall_tampered(tcp)) tprints(" (INJECTED)"); } 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 return 0; }
static int trace_syscall_entering(struct tcb *tcp, unsigned int *sig) { int res, scno_good; scno_good = res = get_scno(tcp); if (res == 0) return res; if (res == 1) res = get_syscall_args(tcp); if (res != 1) { printleader(tcp); tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????"); /* * " <unavailable>" will be added later by the code which * detects ptrace errors. */ goto ret; } #ifdef LINUX_MIPSO32 if (SEN_syscall == tcp->s_ent->sen) decode_mips_subcall(tcp); #endif #if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall) switch (tcp->s_ent->sen) { # ifdef SYS_socket_subcall case SEN_socketcall: decode_socket_subcall(tcp); break; # endif # ifdef SYS_ipc_subcall case SEN_ipc: decode_ipc_subcall(tcp); break; # endif } #endif /* Restrain from fault injection while the trace executes strace code. */ if (hide_log(tcp)) { tcp->qual_flg &= ~QUAL_FAULT; } switch (tcp->s_ent->sen) { case SEN_execve: case SEN_execveat: #if defined SPARC || defined SPARC64 case SEN_execv: #endif tcp->flags &= ~TCB_HIDE_LOG; break; } if (!(tcp->qual_flg & QUAL_TRACE) || (tracing_paths && !pathtrace_match(tcp)) ) { tcp->flags |= TCB_INSYSCALL | TCB_FILTERED; tcp->sys_func_rval = 0; return 0; } tcp->flags &= ~TCB_FILTERED; if (hide_log(tcp)) { res = 0; goto ret; } if (tcp->qual_flg & QUAL_FAULT) inject_syscall_fault_entering(tcp, sig); if (cflag == CFLAG_ONLY_STATS) { res = 0; goto ret; } #ifdef USE_LIBUNWIND if (stack_trace_enabled) { if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) unwind_capture_stacktrace(tcp); } #endif printleader(tcp); tprintf("%s(", tcp->s_ent->sys_name); if (tcp->qual_flg & QUAL_RAW) res = printargs(tcp); else res = tcp->s_ent->sys_func(tcp); fflush(tcp->outf); ret: tcp->flags |= TCB_INSYSCALL; tcp->sys_func_rval = res; /* Measure the entrance time as late as possible to avoid errors. */ if (Tflag || cflag) gettimeofday(&tcp->etime, NULL); return res; }