linux/lib/syscall.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/ptrace.h>
   3#include <linux/sched.h>
   4#include <linux/sched/task_stack.h>
   5#include <linux/export.h>
   6#include <asm/syscall.h>
   7
   8static int collect_syscall(struct task_struct *target, struct syscall_info *info)
   9{
  10        struct pt_regs *regs;
  11
  12        if (!try_get_task_stack(target)) {
  13                /* Task has no stack, so the task isn't in a syscall. */
  14                memset(info, 0, sizeof(*info));
  15                info->data.nr = -1;
  16                return 0;
  17        }
  18
  19        regs = task_pt_regs(target);
  20        if (unlikely(!regs)) {
  21                put_task_stack(target);
  22                return -EAGAIN;
  23        }
  24
  25        info->sp = user_stack_pointer(regs);
  26        info->data.instruction_pointer = instruction_pointer(regs);
  27
  28        info->data.nr = syscall_get_nr(target, regs);
  29        if (info->data.nr != -1L)
  30                syscall_get_arguments(target, regs,
  31                                      (unsigned long *)&info->data.args[0]);
  32
  33        put_task_stack(target);
  34        return 0;
  35}
  36
  37/**
  38 * task_current_syscall - Discover what a blocked task is doing.
  39 * @target:             thread to examine
  40 * @info:               structure with the following fields:
  41 *                       .sp        - filled with user stack pointer
  42 *                       .data.nr   - filled with system call number or -1
  43 *                       .data.args - filled with @maxargs system call arguments
  44 *                       .data.instruction_pointer - filled with user PC
  45 *
  46 * If @target is blocked in a system call, returns zero with @info.data.nr
  47 * set to the the call's number and @info.data.args filled in with its
  48 * arguments. Registers not used for system call arguments may not be available
  49 * and it is not kosher to use &struct user_regset calls while the system
  50 * call is still in progress.  Note we may get this result if @target
  51 * has finished its system call but not yet returned to user mode, such
  52 * as when it's stopped for signal handling or syscall exit tracing.
  53 *
  54 * If @target is blocked in the kernel during a fault or exception,
  55 * returns zero with *@info.data.nr set to -1 and does not fill in
  56 * @info.data.args. If so, it's now safe to examine @target using
  57 * &struct user_regset get() calls as long as we're sure @target won't return
  58 * to user mode.
  59 *
  60 * Returns -%EAGAIN if @target does not remain blocked.
  61 */
  62int task_current_syscall(struct task_struct *target, struct syscall_info *info)
  63{
  64        long state;
  65        unsigned long ncsw;
  66
  67        if (target == current)
  68                return collect_syscall(target, info);
  69
  70        state = target->state;
  71        if (unlikely(!state))
  72                return -EAGAIN;
  73
  74        ncsw = wait_task_inactive(target, state);
  75        if (unlikely(!ncsw) ||
  76            unlikely(collect_syscall(target, info)) ||
  77            unlikely(wait_task_inactive(target, state) != ncsw))
  78                return -EAGAIN;
  79
  80        return 0;
  81}
  82