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