void do_syscall_trace_exit(struct pt_regs *regs) { long errno; /* * We may come here right after calling schedule_user() * in which case we can be in RCU user mode. */ user_exit(); /* * The standard tile calling convention returns the value (or negative * errno) in r0, and zero (or positive errno) in r1. * It saves a couple of cycles on the hot path to do this work in * registers only as we return, rather than updating the in-memory * struct ptregs. */ errno = (long) regs->regs[0]; if (errno < 0 && errno > -4096) regs->regs[1] = -errno; else regs->regs[1] = 0; if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_exit(regs, regs->regs[0]); }
asmlinkage void syscall_trace_exit(struct pt_regs *regs) { if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_exit(regs, regs_return_value(regs)); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT); }
void syscall_trace_leave(struct pt_regs *regs) { if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->ctx.DX[0].U1); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); }
asmlinkage void syscall_trace_exit(struct pt_regs *regs) { audit_syscall_exit(regs); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_exit(regs, syscall_get_return_value(current, regs)); }
/* * Called with IRQs on and fully valid regs. Returns with IRQs off in a * state such that we can immediately switch to user mode. */ __visible void syscall_return_slowpath(struct pt_regs *regs) { struct thread_info *ti = pt_regs_to_thread_info(regs); u32 cached_flags = READ_ONCE(ti->flags); bool step; CT_WARN_ON(ct_state() != CONTEXT_KERNEL); if (WARN(irqs_disabled(), "syscall %ld left IRQs disabled", regs->orig_ax)) local_irq_enable(); /* * First do one-time work. If these work items are enabled, we * want to run them exactly once per syscall exit with IRQs on. */ if (cached_flags & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)) { audit_syscall_exit(regs); if (cached_flags & _TIF_SYSCALL_TRACEPOINT) trace_sys_exit(regs, regs->ax); /* * If TIF_SYSCALL_EMU is set, we only get here because of * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). * We already reported this syscall instruction in * syscall_trace_enter(). */ step = unlikely( (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)) == _TIF_SINGLESTEP); if (step || cached_flags & _TIF_SYSCALL_TRACE) tracehook_report_syscall_exit(regs, step); } #ifdef CONFIG_COMPAT /* * Compat syscalls set TS_COMPAT. Make sure we clear it before * returning to user mode. */ ti->status &= ~TS_COMPAT; #endif local_irq_disable(); prepare_exit_to_usermode(regs); }
/* * Notification of system call entry/exit * - triggered by current->work.syscall_trace */ asmlinkage void syscall_trace_leave(struct pt_regs *regs) { /* * We may come here right after calling schedule_user() * or do_notify_resume(), in which case we can be in RCU * user mode. */ user_exit(); audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs_return_value(regs)); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); user_enter(); }
static void syscall_slow_exit_work(struct pt_regs *regs, u32 cached_flags) { bool step; audit_syscall_exit(regs); if (cached_flags & _TIF_SYSCALL_TRACEPOINT) trace_sys_exit(regs, regs->ax); /* * If TIF_SYSCALL_EMU is set, we only get here because of * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). * We already reported this syscall instruction in * syscall_trace_enter(). */ step = unlikely( (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)) == _TIF_SINGLESTEP); if (step || cached_flags & _TIF_SYSCALL_TRACE) tracehook_report_syscall_exit(regs, step); }