aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-04-05 19:15:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-04-05 19:15:57 -0400
commit970b766cfd3f3cb7275bf51144b1678c547882fc (patch)
treea849cc6dd0f74f412a2c6ee5ceb9443d11221a56
parent7f46774c6480174eb869a3c15167eafac467a6af (diff)
parent32d92586629a8b3637a3c9361709818e25f327ad (diff)
Merge tag 'trace-5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull syscall-get-arguments cleanup and fixes from Steven Rostedt: "Andy Lutomirski approached me to tell me that the syscall_get_arguments() implementation in x86 was horrible and gcc certainly gets it wrong. He said that since the tracepoints only pass in 0 and 6 for i and n repectively, it should be optimized for that case. Inspecting the kernel, I discovered that all users pass in 0 for i and only one file passing in something other than 6 for the number of arguments. That code happens to be my own code used for the special syscall tracing. That can easily be converted to just using 0 and 6 as well, and only copying what is needed. Which is probably the faster path anyway for that case. Along the way, a couple of real fixes came from this as the syscall_get_arguments() function was incorrect for csky and riscv. x86 has been optimized to for the new interface that removes the variable number of arguments, but the other architectures could still use some loving and take more advantage of the simpler interface" * tag 'trace-5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: syscalls: Remove start and number from syscall_set_arguments() args syscalls: Remove start and number from syscall_get_arguments() args csky: Fix syscall_get_arguments() and syscall_set_arguments() riscv: Fix syscall_get_arguments() and syscall_set_arguments() tracing/syscalls: Pass in hardcoded 6 into syscall_get_arguments() ptrace: Remove maxargs from task_current_syscall()
-rw-r--r--arch/arc/include/asm/syscall.h7
-rw-r--r--arch/arm/include/asm/syscall.h47
-rw-r--r--arch/arm64/include/asm/syscall.h46
-rw-r--r--arch/c6x/include/asm/syscall.h79
-rw-r--r--arch/csky/include/asm/syscall.h26
-rw-r--r--arch/h8300/include/asm/syscall.h34
-rw-r--r--arch/hexagon/include/asm/syscall.h4
-rw-r--r--arch/ia64/include/asm/syscall.h13
-rw-r--r--arch/ia64/kernel/ptrace.c7
-rw-r--r--arch/microblaze/include/asm/syscall.h8
-rw-r--r--arch/mips/include/asm/syscall.h3
-rw-r--r--arch/mips/kernel/ptrace.c2
-rw-r--r--arch/nds32/include/asm/syscall.h62
-rw-r--r--arch/nios2/include/asm/syscall.h84
-rw-r--r--arch/openrisc/include/asm/syscall.h12
-rw-r--r--arch/parisc/include/asm/syscall.h30
-rw-r--r--arch/powerpc/include/asm/syscall.h15
-rw-r--r--arch/riscv/include/asm/syscall.h24
-rw-r--r--arch/s390/include/asm/syscall.h28
-rw-r--r--arch/sh/include/asm/syscall_32.h47
-rw-r--r--arch/sh/include/asm/syscall_64.h8
-rw-r--r--arch/sparc/include/asm/syscall.h11
-rw-r--r--arch/um/include/asm/syscall-generic.h78
-rw-r--r--arch/x86/include/asm/syscall.h142
-rw-r--r--arch/xtensa/include/asm/syscall.h33
-rw-r--r--fs/proc/base.c17
-rw-r--r--include/asm-generic/syscall.h21
-rw-r--r--include/linux/ptrace.h11
-rw-r--r--include/trace/events/syscalls.h2
-rw-r--r--kernel/seccomp.c2
-rw-r--r--kernel/trace/trace_syscalls.c9
-rw-r--r--lib/syscall.c57
32 files changed, 247 insertions, 722 deletions
diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 29de09804306..c7a4201ed62b 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -55,12 +55,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
55 */ 55 */
56static inline void 56static inline void
57syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 57syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
58 unsigned int i, unsigned int n, unsigned long *args) 58 unsigned long *args)
59{ 59{
60 unsigned long *inside_ptregs = &(regs->r0); 60 unsigned long *inside_ptregs = &(regs->r0);
61 inside_ptregs -= i; 61 unsigned int n = 6;
62 62 unsigned int i = 0;
63 BUG_ON((i + n) > 6);
64 63
65 while (n--) { 64 while (n--) {
66 args[i++] = (*inside_ptregs); 65 args[i++] = (*inside_ptregs);
diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
index 06dea6bce293..080ce70cab12 100644
--- a/arch/arm/include/asm/syscall.h
+++ b/arch/arm/include/asm/syscall.h
@@ -55,53 +55,22 @@ static inline void syscall_set_return_value(struct task_struct *task,
55 55
56static inline void syscall_get_arguments(struct task_struct *task, 56static inline void syscall_get_arguments(struct task_struct *task,
57 struct pt_regs *regs, 57 struct pt_regs *regs,
58 unsigned int i, unsigned int n,
59 unsigned long *args) 58 unsigned long *args)
60{ 59{
61 if (n == 0) 60 args[0] = regs->ARM_ORIG_r0;
62 return; 61 args++;
63 62
64 if (i + n > SYSCALL_MAX_ARGS) { 63 memcpy(args, &regs->ARM_r0 + 1, 5 * sizeof(args[0]));
65 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
66 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
67 pr_warn("%s called with max args %d, handling only %d\n",
68 __func__, i + n, SYSCALL_MAX_ARGS);
69 memset(args_bad, 0, n_bad * sizeof(args[0]));
70 n = SYSCALL_MAX_ARGS - i;
71 }
72
73 if (i == 0) {
74 args[0] = regs->ARM_ORIG_r0;
75 args++;
76 i++;
77 n--;
78 }
79
80 memcpy(args, &regs->ARM_r0 + i, n * sizeof(args[0]));
81} 64}
82 65
83static inline void syscall_set_arguments(struct task_struct *task, 66static inline void syscall_set_arguments(struct task_struct *task,
84 struct pt_regs *regs, 67 struct pt_regs *regs,
85 unsigned int i, unsigned int n,
86 const unsigned long *args) 68 const unsigned long *args)
87{ 69{
88 if (n == 0) 70 regs->ARM_ORIG_r0 = args[0];
89 return; 71 args++;
90 72
91 if (i + n > SYSCALL_MAX_ARGS) { 73 memcpy(&regs->ARM_r0 + 1, args, 5 * sizeof(args[0]));
92 pr_warn("%s called with max args %d, handling only %d\n",
93 __func__, i + n, SYSCALL_MAX_ARGS);
94 n = SYSCALL_MAX_ARGS - i;
95 }
96
97 if (i == 0) {
98 regs->ARM_ORIG_r0 = args[0];
99 args++;
100 i++;
101 n--;
102 }
103
104 memcpy(&regs->ARM_r0 + i, args, n * sizeof(args[0]));
105} 74}
106 75
107static inline int syscall_get_arch(void) 76static inline int syscall_get_arch(void)
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index ad8be16a39c9..a179df3674a1 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -65,52 +65,22 @@ static inline void syscall_set_return_value(struct task_struct *task,
65 65
66static inline void syscall_get_arguments(struct task_struct *task, 66static inline void syscall_get_arguments(struct task_struct *task,
67 struct pt_regs *regs, 67 struct pt_regs *regs,
68 unsigned int i, unsigned int n,
69 unsigned long *args) 68 unsigned long *args)
70{ 69{
71 if (n == 0) 70 args[0] = regs->orig_x0;
72 return; 71 args++;
73 72
74 if (i + n > SYSCALL_MAX_ARGS) { 73 memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
75 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
76 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
77 pr_warning("%s called with max args %d, handling only %d\n",
78 __func__, i + n, SYSCALL_MAX_ARGS);
79 memset(args_bad, 0, n_bad * sizeof(args[0]));
80 }
81
82 if (i == 0) {
83 args[0] = regs->orig_x0;
84 args++;
85 i++;
86 n--;
87 }
88
89 memcpy(args, &regs->regs[i], n * sizeof(args[0]));
90} 74}
91 75
92static inline void syscall_set_arguments(struct task_struct *task, 76static inline void syscall_set_arguments(struct task_struct *task,
93 struct pt_regs *regs, 77 struct pt_regs *regs,
94 unsigned int i, unsigned int n,
95 const unsigned long *args) 78 const unsigned long *args)
96{ 79{
97 if (n == 0) 80 regs->orig_x0 = args[0];
98 return; 81 args++;
99 82
100 if (i + n > SYSCALL_MAX_ARGS) { 83 memcpy(&regs->regs[1], args, 5 * sizeof(args[0]));
101 pr_warning("%s called with max args %d, handling only %d\n",
102 __func__, i + n, SYSCALL_MAX_ARGS);
103 n = SYSCALL_MAX_ARGS - i;
104 }
105
106 if (i == 0) {
107 regs->orig_x0 = args[0];
108 args++;
109 i++;
110 n--;
111 }
112
113 memcpy(&regs->regs[i], args, n * sizeof(args[0]));
114} 84}
115 85
116/* 86/*
diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h
index ae2be315ee9c..15ba8599858e 100644
--- a/arch/c6x/include/asm/syscall.h
+++ b/arch/c6x/include/asm/syscall.h
@@ -46,78 +46,27 @@ static inline void syscall_set_return_value(struct task_struct *task,
46} 46}
47 47
48static inline void syscall_get_arguments(struct task_struct *task, 48static inline void syscall_get_arguments(struct task_struct *task,
49 struct pt_regs *regs, unsigned int i, 49 struct pt_regs *regs,
50 unsigned int n, unsigned long *args) 50 unsigned long *args)
51{ 51{
52 switch (i) { 52 *args++ = regs->a4;
53 case 0: 53 *args++ = regs->b4;
54 if (!n--) 54 *args++ = regs->a6;
55 break; 55 *args++ = regs->b6;
56 *args++ = regs->a4; 56 *args++ = regs->a8;
57 case 1: 57 *args = regs->b8;
58 if (!n--)
59 break;
60 *args++ = regs->b4;
61 case 2:
62 if (!n--)
63 break;
64 *args++ = regs->a6;
65 case 3:
66 if (!n--)
67 break;
68 *args++ = regs->b6;
69 case 4:
70 if (!n--)
71 break;
72 *args++ = regs->a8;
73 case 5:
74 if (!n--)
75 break;
76 *args++ = regs->b8;
77 case 6:
78 if (!n--)
79 break;
80 default:
81 BUG();
82 }
83} 58}
84 59
85static inline void syscall_set_arguments(struct task_struct *task, 60static inline void syscall_set_arguments(struct task_struct *task,
86 struct pt_regs *regs, 61 struct pt_regs *regs,
87 unsigned int i, unsigned int n,
88 const unsigned long *args) 62 const unsigned long *args)
89{ 63{
90 switch (i) { 64 regs->a4 = *args++;
91 case 0: 65 regs->b4 = *args++;
92 if (!n--) 66 regs->a6 = *args++;
93 break; 67 regs->b6 = *args++;
94 regs->a4 = *args++; 68 regs->a8 = *args++;
95 case 1: 69 regs->a9 = *args;
96 if (!n--)
97 break;
98 regs->b4 = *args++;
99 case 2:
100 if (!n--)
101 break;
102 regs->a6 = *args++;
103 case 3:
104 if (!n--)
105 break;
106 regs->b6 = *args++;
107 case 4:
108 if (!n--)
109 break;
110 regs->a8 = *args++;
111 case 5:
112 if (!n--)
113 break;
114 regs->a9 = *args++;
115 case 6:
116 if (!n)
117 break;
118 default:
119 BUG();
120 }
121} 70}
122 71
123#endif /* __ASM_C6X_SYSCALLS_H */ 72#endif /* __ASM_C6X_SYSCALLS_H */
diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h
index d637445737b7..bda0a446c63e 100644
--- a/arch/csky/include/asm/syscall.h
+++ b/arch/csky/include/asm/syscall.h
@@ -43,30 +43,20 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
43 43
44static inline void 44static inline void
45syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 45syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
46 unsigned int i, unsigned int n, unsigned long *args) 46 unsigned long *args)
47{ 47{
48 BUG_ON(i + n > 6); 48 args[0] = regs->orig_a0;
49 if (i == 0) { 49 args++;
50 args[0] = regs->orig_a0; 50 memcpy(args, &regs->a1, 5 * sizeof(args[0]));
51 args++;
52 i++;
53 n--;
54 }
55 memcpy(args, &regs->a1 + i * sizeof(regs->a1), n * sizeof(args[0]));
56} 51}
57 52
58static inline void 53static inline void
59syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, 54syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
60 unsigned int i, unsigned int n, const unsigned long *args) 55 const unsigned long *args)
61{ 56{
62 BUG_ON(i + n > 6); 57 regs->orig_a0 = args[0];
63 if (i == 0) { 58 args++;
64 regs->orig_a0 = args[0]; 59 memcpy(&regs->a1, args, 5 * sizeof(regs->a1));
65 args++;
66 i++;
67 n--;
68 }
69 memcpy(&regs->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0));
70} 60}
71 61
72static inline int 62static inline int
diff --git a/arch/h8300/include/asm/syscall.h b/arch/h8300/include/asm/syscall.h
index 924990401237..ddd483c6ca95 100644
--- a/arch/h8300/include/asm/syscall.h
+++ b/arch/h8300/include/asm/syscall.h
@@ -17,34 +17,14 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
17 17
18static inline void 18static inline void
19syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 19syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
20 unsigned int i, unsigned int n, unsigned long *args) 20 unsigned long *args)
21{ 21{
22 BUG_ON(i + n > 6); 22 *args++ = regs->er1;
23 23 *args++ = regs->er2;
24 while (n > 0) { 24 *args++ = regs->er3;
25 switch (i) { 25 *args++ = regs->er4;
26 case 0: 26 *args++ = regs->er5;
27 *args++ = regs->er1; 27 *args = regs->er6;
28 break;
29 case 1:
30 *args++ = regs->er2;
31 break;
32 case 2:
33 *args++ = regs->er3;
34 break;
35 case 3:
36 *args++ = regs->er4;
37 break;
38 case 4:
39 *args++ = regs->er5;
40 break;
41 case 5:
42 *args++ = regs->er6;
43 break;
44 }
45 i++;
46 n--;
47 }
48} 28}
49 29
50 30
diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
index 4af9c7b6f13a..ae3a1e24fabd 100644
--- a/arch/hexagon/include/asm/syscall.h
+++ b/arch/hexagon/include/asm/syscall.h
@@ -37,10 +37,8 @@ static inline long syscall_get_nr(struct task_struct *task,
37 37
38static inline void syscall_get_arguments(struct task_struct *task, 38static inline void syscall_get_arguments(struct task_struct *task,
39 struct pt_regs *regs, 39 struct pt_regs *regs,
40 unsigned int i, unsigned int n,
41 unsigned long *args) 40 unsigned long *args)
42{ 41{
43 BUG_ON(i + n > 6); 42 memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
44 memcpy(args, &(&regs->r00)[i], n * sizeof(args[0]));
45} 43}
46#endif 44#endif
diff --git a/arch/ia64/include/asm/syscall.h b/arch/ia64/include/asm/syscall.h
index 1d0b875fec44..0d9e7fab4a79 100644
--- a/arch/ia64/include/asm/syscall.h
+++ b/arch/ia64/include/asm/syscall.h
@@ -59,26 +59,19 @@ static inline void syscall_set_return_value(struct task_struct *task,
59} 59}
60 60
61extern void ia64_syscall_get_set_arguments(struct task_struct *task, 61extern void ia64_syscall_get_set_arguments(struct task_struct *task,
62 struct pt_regs *regs, unsigned int i, unsigned int n, 62 struct pt_regs *regs, unsigned long *args, int rw);
63 unsigned long *args, int rw);
64static inline void syscall_get_arguments(struct task_struct *task, 63static inline void syscall_get_arguments(struct task_struct *task,
65 struct pt_regs *regs, 64 struct pt_regs *regs,
66 unsigned int i, unsigned int n,
67 unsigned long *args) 65 unsigned long *args)
68{ 66{
69 BUG_ON(i + n > 6); 67 ia64_syscall_get_set_arguments(task, regs, args, 0);
70
71 ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
72} 68}
73 69
74static inline void syscall_set_arguments(struct task_struct *task, 70static inline void syscall_set_arguments(struct task_struct *task,
75 struct pt_regs *regs, 71 struct pt_regs *regs,
76 unsigned int i, unsigned int n,
77 unsigned long *args) 72 unsigned long *args)
78{ 73{
79 BUG_ON(i + n > 6); 74 ia64_syscall_get_set_arguments(task, regs, args, 1);
80
81 ia64_syscall_get_set_arguments(task, regs, i, n, args, 1);
82} 75}
83 76
84static inline int syscall_get_arch(void) 77static inline int syscall_get_arch(void)
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 6d50ede0ed69..bf9c24d9ce84 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -2179,12 +2179,11 @@ static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data)
2179} 2179}
2180 2180
2181void ia64_syscall_get_set_arguments(struct task_struct *task, 2181void ia64_syscall_get_set_arguments(struct task_struct *task,
2182 struct pt_regs *regs, unsigned int i, unsigned int n, 2182 struct pt_regs *regs, unsigned long *args, int rw)
2183 unsigned long *args, int rw)
2184{ 2183{
2185 struct syscall_get_set_args data = { 2184 struct syscall_get_set_args data = {
2186 .i = i, 2185 .i = 0,
2187 .n = n, 2186 .n = 6,
2188 .args = args, 2187 .args = args,
2189 .regs = regs, 2188 .regs = regs,
2190 .rw = rw, 2189 .rw = rw,
diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h
index 220decd605a4..833d3a53dab3 100644
--- a/arch/microblaze/include/asm/syscall.h
+++ b/arch/microblaze/include/asm/syscall.h
@@ -82,18 +82,22 @@ static inline void microblaze_set_syscall_arg(struct pt_regs *regs,
82 82
83static inline void syscall_get_arguments(struct task_struct *task, 83static inline void syscall_get_arguments(struct task_struct *task,
84 struct pt_regs *regs, 84 struct pt_regs *regs,
85 unsigned int i, unsigned int n,
86 unsigned long *args) 85 unsigned long *args)
87{ 86{
87 unsigned int i = 0;
88 unsigned int n = 6;
89
88 while (n--) 90 while (n--)
89 *args++ = microblaze_get_syscall_arg(regs, i++); 91 *args++ = microblaze_get_syscall_arg(regs, i++);
90} 92}
91 93
92static inline void syscall_set_arguments(struct task_struct *task, 94static inline void syscall_set_arguments(struct task_struct *task,
93 struct pt_regs *regs, 95 struct pt_regs *regs,
94 unsigned int i, unsigned int n,
95 const unsigned long *args) 96 const unsigned long *args)
96{ 97{
98 unsigned int i = 0;
99 unsigned int n = 6;
100
97 while (n--) 101 while (n--)
98 microblaze_set_syscall_arg(regs, i++, *args++); 102 microblaze_set_syscall_arg(regs, i++, *args++);
99} 103}
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 6cf8ffb5367e..a2b4748655df 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -116,9 +116,10 @@ static inline void syscall_set_return_value(struct task_struct *task,
116 116
117static inline void syscall_get_arguments(struct task_struct *task, 117static inline void syscall_get_arguments(struct task_struct *task,
118 struct pt_regs *regs, 118 struct pt_regs *regs,
119 unsigned int i, unsigned int n,
120 unsigned long *args) 119 unsigned long *args)
121{ 120{
121 unsigned int i = 0;
122 unsigned int n = 6;
122 int ret; 123 int ret;
123 124
124 /* O32 ABI syscall() */ 125 /* O32 ABI syscall() */
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 0057c910bc2f..3a62f80958e1 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1419,7 +1419,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
1419 1419
1420 sd.nr = syscall; 1420 sd.nr = syscall;
1421 sd.arch = syscall_get_arch(); 1421 sd.arch = syscall_get_arch();
1422 syscall_get_arguments(current, regs, 0, 6, args); 1422 syscall_get_arguments(current, regs, args);
1423 for (i = 0; i < 6; i++) 1423 for (i = 0; i < 6; i++)
1424 sd.args[i] = args[i]; 1424 sd.args[i] = args[i];
1425 sd.instruction_pointer = KSTK_EIP(current); 1425 sd.instruction_pointer = KSTK_EIP(current);
diff --git a/arch/nds32/include/asm/syscall.h b/arch/nds32/include/asm/syscall.h
index f7e5e86765fe..671ebd357496 100644
--- a/arch/nds32/include/asm/syscall.h
+++ b/arch/nds32/include/asm/syscall.h
@@ -108,81 +108,41 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
108 * syscall_get_arguments - extract system call parameter values 108 * syscall_get_arguments - extract system call parameter values
109 * @task: task of interest, must be blocked 109 * @task: task of interest, must be blocked
110 * @regs: task_pt_regs() of @task 110 * @regs: task_pt_regs() of @task
111 * @i: argument index [0,5]
112 * @n: number of arguments; n+i must be [1,6].
113 * @args: array filled with argument values 111 * @args: array filled with argument values
114 * 112 *
115 * Fetches @n arguments to the system call starting with the @i'th argument 113 * Fetches 6 arguments to the system call (from 0 through 5). The first
116 * (from 0 through 5). Argument @i is stored in @args[0], and so on. 114 * argument is stored in @args[0], and so on.
117 * An arch inline version is probably optimal when @i and @n are constants.
118 * 115 *
119 * It's only valid to call this when @task is stopped for tracing on 116 * It's only valid to call this when @task is stopped for tracing on
120 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 117 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
121 * It's invalid to call this with @i + @n > 6; we only support system calls
122 * taking up to 6 arguments.
123 */ 118 */
124#define SYSCALL_MAX_ARGS 6 119#define SYSCALL_MAX_ARGS 6
125void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 120void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
126 unsigned int i, unsigned int n, unsigned long *args) 121 unsigned long *args)
127{ 122{
128 if (n == 0) 123 args[0] = regs->orig_r0;
129 return; 124 args++;
130 if (i + n > SYSCALL_MAX_ARGS) { 125 memcpy(args, &regs->uregs[0] + 1, 5 * sizeof(args[0]));
131 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
132 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
133 pr_warning("%s called with max args %d, handling only %d\n",
134 __func__, i + n, SYSCALL_MAX_ARGS);
135 memset(args_bad, 0, n_bad * sizeof(args[0]));
136 memset(args_bad, 0, n_bad * sizeof(args[0]));
137 }
138
139 if (i == 0) {
140 args[0] = regs->orig_r0;
141 args++;
142 i++;
143 n--;
144 }
145
146 memcpy(args, &regs->uregs[0] + i, n * sizeof(args[0]));
147} 126}
148 127
149/** 128/**
150 * syscall_set_arguments - change system call parameter value 129 * syscall_set_arguments - change system call parameter value
151 * @task: task of interest, must be in system call entry tracing 130 * @task: task of interest, must be in system call entry tracing
152 * @regs: task_pt_regs() of @task 131 * @regs: task_pt_regs() of @task
153 * @i: argument index [0,5]
154 * @n: number of arguments; n+i must be [1,6].
155 * @args: array of argument values to store 132 * @args: array of argument values to store
156 * 133 *
157 * Changes @n arguments to the system call starting with the @i'th argument. 134 * Changes 6 arguments to the system call. The first argument gets value
158 * Argument @i gets value @args[0], and so on. 135 * @args[0], and so on.
159 * An arch inline version is probably optimal when @i and @n are constants.
160 * 136 *
161 * It's only valid to call this when @task is stopped for tracing on 137 * It's only valid to call this when @task is stopped for tracing on
162 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 138 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
163 * It's invalid to call this with @i + @n > 6; we only support system calls
164 * taking up to 6 arguments.
165 */ 139 */
166void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, 140void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
167 unsigned int i, unsigned int n,
168 const unsigned long *args) 141 const unsigned long *args)
169{ 142{
170 if (n == 0) 143 regs->orig_r0 = args[0];
171 return; 144 args++;
172
173 if (i + n > SYSCALL_MAX_ARGS) {
174 pr_warn("%s called with max args %d, handling only %d\n",
175 __func__, i + n, SYSCALL_MAX_ARGS);
176 n = SYSCALL_MAX_ARGS - i;
177 }
178
179 if (i == 0) {
180 regs->orig_r0 = args[0];
181 args++;
182 i++;
183 n--;
184 }
185 145
186 memcpy(&regs->uregs[0] + i, args, n * sizeof(args[0])); 146 memcpy(&regs->uregs[0] + 1, args, 5 * sizeof(args[0]));
187} 147}
188#endif /* _ASM_NDS32_SYSCALL_H */ 148#endif /* _ASM_NDS32_SYSCALL_H */
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
index 9de220854c4a..d7624ed06efb 100644
--- a/arch/nios2/include/asm/syscall.h
+++ b/arch/nios2/include/asm/syscall.h
@@ -58,81 +58,25 @@ static inline void syscall_set_return_value(struct task_struct *task,
58} 58}
59 59
60static inline void syscall_get_arguments(struct task_struct *task, 60static inline void syscall_get_arguments(struct task_struct *task,
61 struct pt_regs *regs, unsigned int i, unsigned int n, 61 struct pt_regs *regs, unsigned long *args)
62 unsigned long *args)
63{ 62{
64 BUG_ON(i + n > 6); 63 *args++ = regs->r4;
65 64 *args++ = regs->r5;
66 switch (i) { 65 *args++ = regs->r6;
67 case 0: 66 *args++ = regs->r7;
68 if (!n--) 67 *args++ = regs->r8;
69 break; 68 *args = regs->r9;
70 *args++ = regs->r4;
71 case 1:
72 if (!n--)
73 break;
74 *args++ = regs->r5;
75 case 2:
76 if (!n--)
77 break;
78 *args++ = regs->r6;
79 case 3:
80 if (!n--)
81 break;
82 *args++ = regs->r7;
83 case 4:
84 if (!n--)
85 break;
86 *args++ = regs->r8;
87 case 5:
88 if (!n--)
89 break;
90 *args++ = regs->r9;
91 case 6:
92 if (!n--)
93 break;
94 default:
95 BUG();
96 }
97} 69}
98 70
99static inline void syscall_set_arguments(struct task_struct *task, 71static inline void syscall_set_arguments(struct task_struct *task,
100 struct pt_regs *regs, unsigned int i, unsigned int n, 72 struct pt_regs *regs, const unsigned long *args)
101 const unsigned long *args)
102{ 73{
103 BUG_ON(i + n > 6); 74 regs->r4 = *args++;
104 75 regs->r5 = *args++;
105 switch (i) { 76 regs->r6 = *args++;
106 case 0: 77 regs->r7 = *args++;
107 if (!n--) 78 regs->r8 = *args++;
108 break; 79 regs->r9 = *args;
109 regs->r4 = *args++;
110 case 1:
111 if (!n--)
112 break;
113 regs->r5 = *args++;
114 case 2:
115 if (!n--)
116 break;
117 regs->r6 = *args++;
118 case 3:
119 if (!n--)
120 break;
121 regs->r7 = *args++;
122 case 4:
123 if (!n--)
124 break;
125 regs->r8 = *args++;
126 case 5:
127 if (!n--)
128 break;
129 regs->r9 = *args++;
130 case 6:
131 if (!n)
132 break;
133 default:
134 BUG();
135 }
136} 80}
137 81
138#endif 82#endif
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
index 2db9f1cf0694..b4ff07c1baed 100644
--- a/arch/openrisc/include/asm/syscall.h
+++ b/arch/openrisc/include/asm/syscall.h
@@ -56,20 +56,16 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
56 56
57static inline void 57static inline void
58syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 58syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
59 unsigned int i, unsigned int n, unsigned long *args) 59 unsigned long *args)
60{ 60{
61 BUG_ON(i + n > 6); 61 memcpy(args, &regs->gpr[3], 6 * sizeof(args[0]));
62
63 memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
64} 62}
65 63
66static inline void 64static inline void
67syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, 65syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
68 unsigned int i, unsigned int n, const unsigned long *args) 66 const unsigned long *args)
69{ 67{
70 BUG_ON(i + n > 6); 68 memcpy(&regs->gpr[3], args, 6 * sizeof(args[0]));
71
72 memcpy(&regs->gpr[3 + i], args, n * sizeof(args[0]));
73} 69}
74 70
75static inline int syscall_get_arch(void) 71static inline int syscall_get_arch(void)
diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
index 8bff1a58c97f..62a6d477fae0 100644
--- a/arch/parisc/include/asm/syscall.h
+++ b/arch/parisc/include/asm/syscall.h
@@ -18,29 +18,15 @@ static inline long syscall_get_nr(struct task_struct *tsk,
18} 18}
19 19
20static inline void syscall_get_arguments(struct task_struct *tsk, 20static inline void syscall_get_arguments(struct task_struct *tsk,
21 struct pt_regs *regs, unsigned int i, 21 struct pt_regs *regs,
22 unsigned int n, unsigned long *args) 22 unsigned long *args)
23{ 23{
24 BUG_ON(i); 24 args[5] = regs->gr[21];
25 25 args[4] = regs->gr[22];
26 switch (n) { 26 args[3] = regs->gr[23];
27 case 6: 27 args[2] = regs->gr[24];
28 args[5] = regs->gr[21]; 28 args[1] = regs->gr[25];
29 case 5: 29 args[0] = regs->gr[26];
30 args[4] = regs->gr[22];
31 case 4:
32 args[3] = regs->gr[23];
33 case 3:
34 args[2] = regs->gr[24];
35 case 2:
36 args[1] = regs->gr[25];
37 case 1:
38 args[0] = regs->gr[26];
39 case 0:
40 break;
41 default:
42 BUG();
43 }
44} 30}
45 31
46static inline long syscall_get_return_value(struct task_struct *task, 32static inline long syscall_get_return_value(struct task_struct *task,
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 1a0e7a8b1c81..1243045bad2d 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -65,22 +65,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
65 65
66static inline void syscall_get_arguments(struct task_struct *task, 66static inline void syscall_get_arguments(struct task_struct *task,
67 struct pt_regs *regs, 67 struct pt_regs *regs,
68 unsigned int i, unsigned int n,
69 unsigned long *args) 68 unsigned long *args)
70{ 69{
71 unsigned long val, mask = -1UL; 70 unsigned long val, mask = -1UL;
72 71 unsigned int n = 6;
73 BUG_ON(i + n > 6);
74 72
75#ifdef CONFIG_COMPAT 73#ifdef CONFIG_COMPAT
76 if (test_tsk_thread_flag(task, TIF_32BIT)) 74 if (test_tsk_thread_flag(task, TIF_32BIT))
77 mask = 0xffffffff; 75 mask = 0xffffffff;
78#endif 76#endif
79 while (n--) { 77 while (n--) {
80 if (n == 0 && i == 0) 78 if (n == 0)
81 val = regs->orig_gpr3; 79 val = regs->orig_gpr3;
82 else 80 else
83 val = regs->gpr[3 + i + n]; 81 val = regs->gpr[3 + n];
84 82
85 args[n] = val & mask; 83 args[n] = val & mask;
86 } 84 }
@@ -88,15 +86,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
88 86
89static inline void syscall_set_arguments(struct task_struct *task, 87static inline void syscall_set_arguments(struct task_struct *task,
90 struct pt_regs *regs, 88 struct pt_regs *regs,
91 unsigned int i, unsigned int n,
92 const unsigned long *args) 89 const unsigned long *args)
93{ 90{
94 BUG_ON(i + n > 6); 91 memcpy(&regs->gpr[3], args, 6 * sizeof(args[0]));
95 memcpy(&regs->gpr[3 + i], args, n * sizeof(args[0]));
96 92
97 /* Also copy the first argument into orig_gpr3 */ 93 /* Also copy the first argument into orig_gpr3 */
98 if (i == 0 && n > 0) 94 regs->orig_gpr3 = args[0];
99 regs->orig_gpr3 = args[0];
100} 95}
101 96
102static inline int syscall_get_arch(void) 97static inline int syscall_get_arch(void)
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
index bba3da6ef157..a3d5273ded7c 100644
--- a/arch/riscv/include/asm/syscall.h
+++ b/arch/riscv/include/asm/syscall.h
@@ -72,32 +72,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
72 72
73static inline void syscall_get_arguments(struct task_struct *task, 73static inline void syscall_get_arguments(struct task_struct *task,
74 struct pt_regs *regs, 74 struct pt_regs *regs,
75 unsigned int i, unsigned int n,
76 unsigned long *args) 75 unsigned long *args)
77{ 76{
78 BUG_ON(i + n > 6); 77 args[0] = regs->orig_a0;
79 if (i == 0) { 78 args++;
80 args[0] = regs->orig_a0; 79 memcpy(args, &regs->a1, 5 * sizeof(args[0]));
81 args++;
82 i++;
83 n--;
84 }
85 memcpy(args, &regs->a1 + i * sizeof(regs->a1), n * sizeof(args[0]));
86} 80}
87 81
88static inline void syscall_set_arguments(struct task_struct *task, 82static inline void syscall_set_arguments(struct task_struct *task,
89 struct pt_regs *regs, 83 struct pt_regs *regs,
90 unsigned int i, unsigned int n,
91 const unsigned long *args) 84 const unsigned long *args)
92{ 85{
93 BUG_ON(i + n > 6); 86 regs->orig_a0 = args[0];
94 if (i == 0) { 87 args++;
95 regs->orig_a0 = args[0]; 88 memcpy(&regs->a1, args, 5 * sizeof(regs->a1));
96 args++;
97 i++;
98 n--;
99 }
100 memcpy(&regs->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0));
101} 89}
102 90
103static inline int syscall_get_arch(void) 91static inline int syscall_get_arch(void)
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 96f9a9151fde..59c3e91f2cdb 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -56,40 +56,32 @@ static inline void syscall_set_return_value(struct task_struct *task,
56 56
57static inline void syscall_get_arguments(struct task_struct *task, 57static inline void syscall_get_arguments(struct task_struct *task,
58 struct pt_regs *regs, 58 struct pt_regs *regs,
59 unsigned int i, unsigned int n,
60 unsigned long *args) 59 unsigned long *args)
61{ 60{
62 unsigned long mask = -1UL; 61 unsigned long mask = -1UL;
62 unsigned int n = 6;
63 63
64 /*
65 * No arguments for this syscall, there's nothing to do.
66 */
67 if (!n)
68 return;
69
70 BUG_ON(i + n > 6);
71#ifdef CONFIG_COMPAT 64#ifdef CONFIG_COMPAT
72 if (test_tsk_thread_flag(task, TIF_31BIT)) 65 if (test_tsk_thread_flag(task, TIF_31BIT))
73 mask = 0xffffffff; 66 mask = 0xffffffff;
74#endif 67#endif
75 while (n-- > 0) 68 while (n-- > 0)
76 if (i + n > 0) 69 if (n > 0)
77 args[n] = regs->gprs[2 + i + n] & mask; 70 args[n] = regs->gprs[2 + n] & mask;
78 if (i == 0) 71
79 args[0] = regs->orig_gpr2 & mask; 72 args[0] = regs->orig_gpr2 & mask;
80} 73}
81 74
82static inline void syscall_set_arguments(struct task_struct *task, 75static inline void syscall_set_arguments(struct task_struct *task,
83 struct pt_regs *regs, 76 struct pt_regs *regs,
84 unsigned int i, unsigned int n,
85 const unsigned long *args) 77 const unsigned long *args)
86{ 78{
87 BUG_ON(i + n > 6); 79 unsigned int n = 6;
80
88 while (n-- > 0) 81 while (n-- > 0)
89 if (i + n > 0) 82 if (n > 0)
90 regs->gprs[2 + i + n] = args[n]; 83 regs->gprs[2 + n] = args[n];
91 if (i == 0) 84 regs->orig_gpr2 = args[0];
92 regs->orig_gpr2 = args[0];
93} 85}
94 86
95static inline int syscall_get_arch(void) 87static inline int syscall_get_arch(void)
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index 6e118799831c..8c9d7e5e5dcc 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -48,51 +48,28 @@ static inline void syscall_set_return_value(struct task_struct *task,
48 48
49static inline void syscall_get_arguments(struct task_struct *task, 49static inline void syscall_get_arguments(struct task_struct *task,
50 struct pt_regs *regs, 50 struct pt_regs *regs,
51 unsigned int i, unsigned int n,
52 unsigned long *args) 51 unsigned long *args)
53{ 52{
54 /*
55 * Do this simply for now. If we need to start supporting
56 * fetching arguments from arbitrary indices, this will need some
57 * extra logic. Presently there are no in-tree users that depend
58 * on this behaviour.
59 */
60 BUG_ON(i);
61 53
62 /* Argument pattern is: R4, R5, R6, R7, R0, R1 */ 54 /* Argument pattern is: R4, R5, R6, R7, R0, R1 */
63 switch (n) { 55 args[5] = regs->regs[1];
64 case 6: args[5] = regs->regs[1]; 56 args[4] = regs->regs[0];
65 case 5: args[4] = regs->regs[0]; 57 args[3] = regs->regs[7];
66 case 4: args[3] = regs->regs[7]; 58 args[2] = regs->regs[6];
67 case 3: args[2] = regs->regs[6]; 59 args[1] = regs->regs[5];
68 case 2: args[1] = regs->regs[5]; 60 args[0] = regs->regs[4];
69 case 1: args[0] = regs->regs[4];
70 case 0:
71 break;
72 default:
73 BUG();
74 }
75} 61}
76 62
77static inline void syscall_set_arguments(struct task_struct *task, 63static inline void syscall_set_arguments(struct task_struct *task,
78 struct pt_regs *regs, 64 struct pt_regs *regs,
79 unsigned int i, unsigned int n,
80 const unsigned long *args) 65 const unsigned long *args)
81{ 66{
82 /* Same note as above applies */ 67 regs->regs[1] = args[5];
83 BUG_ON(i); 68 regs->regs[0] = args[4];
84 69 regs->regs[7] = args[3];
85 switch (n) { 70 regs->regs[6] = args[2];
86 case 6: regs->regs[1] = args[5]; 71 regs->regs[5] = args[1];
87 case 5: regs->regs[0] = args[4]; 72 regs->regs[4] = args[0];
88 case 4: regs->regs[7] = args[3];
89 case 3: regs->regs[6] = args[2];
90 case 2: regs->regs[5] = args[1];
91 case 1: regs->regs[4] = args[0];
92 break;
93 default:
94 BUG();
95 }
96} 73}
97 74
98static inline int syscall_get_arch(void) 75static inline int syscall_get_arch(void)
diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h
index 43882580c7f9..22fad97da066 100644
--- a/arch/sh/include/asm/syscall_64.h
+++ b/arch/sh/include/asm/syscall_64.h
@@ -47,20 +47,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
47 47
48static inline void syscall_get_arguments(struct task_struct *task, 48static inline void syscall_get_arguments(struct task_struct *task,
49 struct pt_regs *regs, 49 struct pt_regs *regs,
50 unsigned int i, unsigned int n,
51 unsigned long *args) 50 unsigned long *args)
52{ 51{
53 BUG_ON(i + n > 6); 52 memcpy(args, &regs->regs[2], 6 * sizeof(args[0]));
54 memcpy(args, &regs->regs[2 + i], n * sizeof(args[0]));
55} 53}
56 54
57static inline void syscall_set_arguments(struct task_struct *task, 55static inline void syscall_set_arguments(struct task_struct *task,
58 struct pt_regs *regs, 56 struct pt_regs *regs,
59 unsigned int i, unsigned int n,
60 const unsigned long *args) 57 const unsigned long *args)
61{ 58{
62 BUG_ON(i + n > 6); 59 memcpy(&regs->regs[2], args, 6 * sizeof(args[0]));
63 memcpy(&regs->regs[2 + i], args, n * sizeof(args[0]));
64} 60}
65 61
66static inline int syscall_get_arch(void) 62static inline int syscall_get_arch(void)
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
index 053989e3f6a6..4d075434e816 100644
--- a/arch/sparc/include/asm/syscall.h
+++ b/arch/sparc/include/asm/syscall.h
@@ -96,11 +96,11 @@ static inline void syscall_set_return_value(struct task_struct *task,
96 96
97static inline void syscall_get_arguments(struct task_struct *task, 97static inline void syscall_get_arguments(struct task_struct *task,
98 struct pt_regs *regs, 98 struct pt_regs *regs,
99 unsigned int i, unsigned int n,
100 unsigned long *args) 99 unsigned long *args)
101{ 100{
102 int zero_extend = 0; 101 int zero_extend = 0;
103 unsigned int j; 102 unsigned int j;
103 unsigned int n = 6;
104 104
105#ifdef CONFIG_SPARC64 105#ifdef CONFIG_SPARC64
106 if (test_tsk_thread_flag(task, TIF_32BIT)) 106 if (test_tsk_thread_flag(task, TIF_32BIT))
@@ -108,7 +108,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
108#endif 108#endif
109 109
110 for (j = 0; j < n; j++) { 110 for (j = 0; j < n; j++) {
111 unsigned long val = regs->u_regs[UREG_I0 + i + j]; 111 unsigned long val = regs->u_regs[UREG_I0 + j];
112 112
113 if (zero_extend) 113 if (zero_extend)
114 args[j] = (u32) val; 114 args[j] = (u32) val;
@@ -119,13 +119,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
119 119
120static inline void syscall_set_arguments(struct task_struct *task, 120static inline void syscall_set_arguments(struct task_struct *task,
121 struct pt_regs *regs, 121 struct pt_regs *regs,
122 unsigned int i, unsigned int n,
123 const unsigned long *args) 122 const unsigned long *args)
124{ 123{
125 unsigned int j; 124 unsigned int i;
126 125
127 for (j = 0; j < n; j++) 126 for (i = 0; i < 6; i++)
128 regs->u_regs[UREG_I0 + i + j] = args[j]; 127 regs->u_regs[UREG_I0 + i] = args[i];
129} 128}
130 129
131static inline int syscall_get_arch(void) 130static inline int syscall_get_arch(void)
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
index 9fb9cf8cd39a..98e50c50c12e 100644
--- a/arch/um/include/asm/syscall-generic.h
+++ b/arch/um/include/asm/syscall-generic.h
@@ -53,84 +53,30 @@ static inline void syscall_set_return_value(struct task_struct *task,
53 53
54static inline void syscall_get_arguments(struct task_struct *task, 54static inline void syscall_get_arguments(struct task_struct *task,
55 struct pt_regs *regs, 55 struct pt_regs *regs,
56 unsigned int i, unsigned int n,
57 unsigned long *args) 56 unsigned long *args)
58{ 57{
59 const struct uml_pt_regs *r = &regs->regs; 58 const struct uml_pt_regs *r = &regs->regs;
60 59
61 switch (i) { 60 *args++ = UPT_SYSCALL_ARG1(r);
62 case 0: 61 *args++ = UPT_SYSCALL_ARG2(r);
63 if (!n--) 62 *args++ = UPT_SYSCALL_ARG3(r);
64 break; 63 *args++ = UPT_SYSCALL_ARG4(r);
65 *args++ = UPT_SYSCALL_ARG1(r); 64 *args++ = UPT_SYSCALL_ARG5(r);
66 case 1: 65 *args = UPT_SYSCALL_ARG6(r);
67 if (!n--)
68 break;
69 *args++ = UPT_SYSCALL_ARG2(r);
70 case 2:
71 if (!n--)
72 break;
73 *args++ = UPT_SYSCALL_ARG3(r);
74 case 3:
75 if (!n--)
76 break;
77 *args++ = UPT_SYSCALL_ARG4(r);
78 case 4:
79 if (!n--)
80 break;
81 *args++ = UPT_SYSCALL_ARG5(r);
82 case 5:
83 if (!n--)
84 break;
85 *args++ = UPT_SYSCALL_ARG6(r);
86 case 6:
87 if (!n--)
88 break;
89 default:
90 BUG();
91 break;
92 }
93} 66}
94 67
95static inline void syscall_set_arguments(struct task_struct *task, 68static inline void syscall_set_arguments(struct task_struct *task,
96 struct pt_regs *regs, 69 struct pt_regs *regs,
97 unsigned int i, unsigned int n,
98 const unsigned long *args) 70 const unsigned long *args)
99{ 71{
100 struct uml_pt_regs *r = &regs->regs; 72 struct uml_pt_regs *r = &regs->regs;
101 73
102 switch (i) { 74 UPT_SYSCALL_ARG1(r) = *args++;
103 case 0: 75 UPT_SYSCALL_ARG2(r) = *args++;
104 if (!n--) 76 UPT_SYSCALL_ARG3(r) = *args++;
105 break; 77 UPT_SYSCALL_ARG4(r) = *args++;
106 UPT_SYSCALL_ARG1(r) = *args++; 78 UPT_SYSCALL_ARG5(r) = *args++;
107 case 1: 79 UPT_SYSCALL_ARG6(r) = *args;
108 if (!n--)
109 break;
110 UPT_SYSCALL_ARG2(r) = *args++;
111 case 2:
112 if (!n--)
113 break;
114 UPT_SYSCALL_ARG3(r) = *args++;
115 case 3:
116 if (!n--)
117 break;
118 UPT_SYSCALL_ARG4(r) = *args++;
119 case 4:
120 if (!n--)
121 break;
122 UPT_SYSCALL_ARG5(r) = *args++;
123 case 5:
124 if (!n--)
125 break;
126 UPT_SYSCALL_ARG6(r) = *args++;
127 case 6:
128 if (!n--)
129 break;
130 default:
131 BUG();
132 break;
133 }
134} 80}
135 81
136/* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ 82/* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index d653139857af..4c305471ec33 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -91,11 +91,9 @@ static inline void syscall_set_return_value(struct task_struct *task,
91 91
92static inline void syscall_get_arguments(struct task_struct *task, 92static inline void syscall_get_arguments(struct task_struct *task,
93 struct pt_regs *regs, 93 struct pt_regs *regs,
94 unsigned int i, unsigned int n,
95 unsigned long *args) 94 unsigned long *args)
96{ 95{
97 BUG_ON(i + n > 6); 96 memcpy(args, &regs->bx, 6 * sizeof(args[0]));
98 memcpy(args, &regs->bx + i, n * sizeof(args[0]));
99} 97}
100 98
101static inline void syscall_set_arguments(struct task_struct *task, 99static inline void syscall_set_arguments(struct task_struct *task,
@@ -116,124 +114,50 @@ static inline int syscall_get_arch(void)
116 114
117static inline void syscall_get_arguments(struct task_struct *task, 115static inline void syscall_get_arguments(struct task_struct *task,
118 struct pt_regs *regs, 116 struct pt_regs *regs,
119 unsigned int i, unsigned int n,
120 unsigned long *args) 117 unsigned long *args)
121{ 118{
122# ifdef CONFIG_IA32_EMULATION 119# ifdef CONFIG_IA32_EMULATION
123 if (task->thread_info.status & TS_COMPAT) 120 if (task->thread_info.status & TS_COMPAT) {
124 switch (i) { 121 *args++ = regs->bx;
125 case 0: 122 *args++ = regs->cx;
126 if (!n--) break; 123 *args++ = regs->dx;
127 *args++ = regs->bx; 124 *args++ = regs->si;
128 case 1: 125 *args++ = regs->di;
129 if (!n--) break; 126 *args = regs->bp;
130 *args++ = regs->cx; 127 } else
131 case 2:
132 if (!n--) break;
133 *args++ = regs->dx;
134 case 3:
135 if (!n--) break;
136 *args++ = regs->si;
137 case 4:
138 if (!n--) break;
139 *args++ = regs->di;
140 case 5:
141 if (!n--) break;
142 *args++ = regs->bp;
143 case 6:
144 if (!n--) break;
145 default:
146 BUG();
147 break;
148 }
149 else
150# endif 128# endif
151 switch (i) { 129 {
152 case 0: 130 *args++ = regs->di;
153 if (!n--) break; 131 *args++ = regs->si;
154 *args++ = regs->di; 132 *args++ = regs->dx;
155 case 1: 133 *args++ = regs->r10;
156 if (!n--) break; 134 *args++ = regs->r8;
157 *args++ = regs->si; 135 *args = regs->r9;
158 case 2: 136 }
159 if (!n--) break;
160 *args++ = regs->dx;
161 case 3:
162 if (!n--) break;
163 *args++ = regs->r10;
164 case 4:
165 if (!n--) break;
166 *args++ = regs->r8;
167 case 5:
168 if (!n--) break;
169 *args++ = regs->r9;
170 case 6:
171 if (!n--) break;
172 default:
173 BUG();
174 break;
175 }
176} 137}
177 138
178static inline void syscall_set_arguments(struct task_struct *task, 139static inline void syscall_set_arguments(struct task_struct *task,
179 struct pt_regs *regs, 140 struct pt_regs *regs,
180 unsigned int i, unsigned int n,
181 const unsigned long *args) 141 const unsigned long *args)
182{ 142{
183# ifdef CONFIG_IA32_EMULATION 143# ifdef CONFIG_IA32_EMULATION
184 if (task->thread_info.status & TS_COMPAT) 144 if (task->thread_info.status & TS_COMPAT) {
185 switch (i) { 145 regs->bx = *args++;
186 case 0: 146 regs->cx = *args++;
187 if (!n--) break; 147 regs->dx = *args++;
188 regs->bx = *args++; 148 regs->si = *args++;
189 case 1: 149 regs->di = *args++;
190 if (!n--) break; 150 regs->bp = *args;
191 regs->cx = *args++; 151 } else
192 case 2:
193 if (!n--) break;
194 regs->dx = *args++;
195 case 3:
196 if (!n--) break;
197 regs->si = *args++;
198 case 4:
199 if (!n--) break;
200 regs->di = *args++;
201 case 5:
202 if (!n--) break;
203 regs->bp = *args++;
204 case 6:
205 if (!n--) break;
206 default:
207 BUG();
208 break;
209 }
210 else
211# endif 152# endif
212 switch (i) { 153 {
213 case 0: 154 regs->di = *args++;
214 if (!n--) break; 155 regs->si = *args++;
215 regs->di = *args++; 156 regs->dx = *args++;
216 case 1: 157 regs->r10 = *args++;
217 if (!n--) break; 158 regs->r8 = *args++;
218 regs->si = *args++; 159 regs->r9 = *args;
219 case 2: 160 }
220 if (!n--) break;
221 regs->dx = *args++;
222 case 3:
223 if (!n--) break;
224 regs->r10 = *args++;
225 case 4:
226 if (!n--) break;
227 regs->r8 = *args++;
228 case 5:
229 if (!n--) break;
230 regs->r9 = *args++;
231 case 6:
232 if (!n--) break;
233 default:
234 BUG();
235 break;
236 }
237} 161}
238 162
239static inline int syscall_get_arch(void) 163static inline int syscall_get_arch(void)
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index a168bf81c7f4..91dc06d58060 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -59,45 +59,24 @@ static inline void syscall_set_return_value(struct task_struct *task,
59 59
60static inline void syscall_get_arguments(struct task_struct *task, 60static inline void syscall_get_arguments(struct task_struct *task,
61 struct pt_regs *regs, 61 struct pt_regs *regs,
62 unsigned int i, unsigned int n,
63 unsigned long *args) 62 unsigned long *args)
64{ 63{
65 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; 64 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS;
66 unsigned int j; 65 unsigned int i;
67 66
68 if (n == 0) 67 for (i = 0; i < 6; ++i)
69 return; 68 args[i] = regs->areg[reg[i]];
70
71 WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS);
72
73 for (j = 0; j < n; ++j) {
74 if (i + j < SYSCALL_MAX_ARGS)
75 args[j] = regs->areg[reg[i + j]];
76 else
77 args[j] = 0;
78 }
79} 69}
80 70
81static inline void syscall_set_arguments(struct task_struct *task, 71static inline void syscall_set_arguments(struct task_struct *task,
82 struct pt_regs *regs, 72 struct pt_regs *regs,
83 unsigned int i, unsigned int n,
84 const unsigned long *args) 73 const unsigned long *args)
85{ 74{
86 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; 75 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS;
87 unsigned int j; 76 unsigned int i;
88
89 if (n == 0)
90 return;
91
92 if (WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS)) {
93 if (i < SYSCALL_MAX_ARGS)
94 n = SYSCALL_MAX_ARGS - i;
95 else
96 return;
97 }
98 77
99 for (j = 0; j < n; ++j) 78 for (i = 0; i < 6; ++i)
100 regs->areg[reg[i + j]] = args[j]; 79 regs->areg[reg[i]] = args[i];
101} 80}
102 81
103asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); 82asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ddef482f1334..6a803a0b75df 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -616,24 +616,25 @@ static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns,
616static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, 616static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns,
617 struct pid *pid, struct task_struct *task) 617 struct pid *pid, struct task_struct *task)
618{ 618{
619 long nr; 619 struct syscall_info info;
620 unsigned long args[6], sp, pc; 620 u64 *args = &info.data.args[0];
621 int res; 621 int res;
622 622
623 res = lock_trace(task); 623 res = lock_trace(task);
624 if (res) 624 if (res)
625 return res; 625 return res;
626 626
627 if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) 627 if (task_current_syscall(task, &info))
628 seq_puts(m, "running\n"); 628 seq_puts(m, "running\n");
629 else if (nr < 0) 629 else if (info.data.nr < 0)
630 seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc); 630 seq_printf(m, "%d 0x%llx 0x%llx\n",
631 info.data.nr, info.sp, info.data.instruction_pointer);
631 else 632 else
632 seq_printf(m, 633 seq_printf(m,
633 "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 634 "%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
634 nr, 635 info.data.nr,
635 args[0], args[1], args[2], args[3], args[4], args[5], 636 args[0], args[1], args[2], args[3], args[4], args[5],
636 sp, pc); 637 info.sp, info.data.instruction_pointer);
637 unlock_trace(task); 638 unlock_trace(task);
638 639
639 return 0; 640 return 0;
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index 0c938a4354f6..b88239e9efe4 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -105,41 +105,30 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
105 * syscall_get_arguments - extract system call parameter values 105 * syscall_get_arguments - extract system call parameter values
106 * @task: task of interest, must be blocked 106 * @task: task of interest, must be blocked
107 * @regs: task_pt_regs() of @task 107 * @regs: task_pt_regs() of @task
108 * @i: argument index [0,5]
109 * @n: number of arguments; n+i must be [1,6].
110 * @args: array filled with argument values 108 * @args: array filled with argument values
111 * 109 *
112 * Fetches @n arguments to the system call starting with the @i'th argument 110 * Fetches 6 arguments to the system call. First argument is stored in
113 * (from 0 through 5). Argument @i is stored in @args[0], and so on. 111* @args[0], and so on.
114 * An arch inline version is probably optimal when @i and @n are constants.
115 * 112 *
116 * It's only valid to call this when @task is stopped for tracing on 113 * It's only valid to call this when @task is stopped for tracing on
117 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 114 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
118 * It's invalid to call this with @i + @n > 6; we only support system calls
119 * taking up to 6 arguments.
120 */ 115 */
121void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 116void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
122 unsigned int i, unsigned int n, unsigned long *args); 117 unsigned long *args);
123 118
124/** 119/**
125 * syscall_set_arguments - change system call parameter value 120 * syscall_set_arguments - change system call parameter value
126 * @task: task of interest, must be in system call entry tracing 121 * @task: task of interest, must be in system call entry tracing
127 * @regs: task_pt_regs() of @task 122 * @regs: task_pt_regs() of @task
128 * @i: argument index [0,5]
129 * @n: number of arguments; n+i must be [1,6].
130 * @args: array of argument values to store 123 * @args: array of argument values to store
131 * 124 *
132 * Changes @n arguments to the system call starting with the @i'th argument. 125 * Changes 6 arguments to the system call.
133 * Argument @i gets value @args[0], and so on. 126 * The first argument gets value @args[0], and so on.
134 * An arch inline version is probably optimal when @i and @n are constants.
135 * 127 *
136 * It's only valid to call this when @task is stopped for tracing on 128 * It's only valid to call this when @task is stopped for tracing on
137 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 129 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
138 * It's invalid to call this with @i + @n > 6; we only support system calls
139 * taking up to 6 arguments.
140 */ 130 */
141void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, 131void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
142 unsigned int i, unsigned int n,
143 const unsigned long *args); 132 const unsigned long *args);
144 133
145/** 134/**
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index edb9b040c94c..d5084ebd9f03 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -9,6 +9,13 @@
9#include <linux/bug.h> /* For BUG_ON. */ 9#include <linux/bug.h> /* For BUG_ON. */
10#include <linux/pid_namespace.h> /* For task_active_pid_ns. */ 10#include <linux/pid_namespace.h> /* For task_active_pid_ns. */
11#include <uapi/linux/ptrace.h> 11#include <uapi/linux/ptrace.h>
12#include <linux/seccomp.h>
13
14/* Add sp to seccomp_data, as seccomp is user API, we don't want to modify it */
15struct syscall_info {
16 __u64 sp;
17 struct seccomp_data data;
18};
12 19
13extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, 20extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr,
14 void *buf, int len, unsigned int gup_flags); 21 void *buf, int len, unsigned int gup_flags);
@@ -407,9 +414,7 @@ static inline void user_single_step_report(struct pt_regs *regs)
407#define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) 414#define current_user_stack_pointer() user_stack_pointer(current_pt_regs())
408#endif 415#endif
409 416
410extern int task_current_syscall(struct task_struct *target, long *callno, 417extern int task_current_syscall(struct task_struct *target, struct syscall_info *info);
411 unsigned long args[6], unsigned int maxargs,
412 unsigned long *sp, unsigned long *pc);
413 418
414extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact); 419extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact);
415#endif 420#endif
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h
index 44a3259ed4a5..b6e0cbc2c71f 100644
--- a/include/trace/events/syscalls.h
+++ b/include/trace/events/syscalls.h
@@ -28,7 +28,7 @@ TRACE_EVENT_FN(sys_enter,
28 28
29 TP_fast_assign( 29 TP_fast_assign(
30 __entry->id = id; 30 __entry->id = id;
31 syscall_get_arguments(current, regs, 0, 6, __entry->args); 31 syscall_get_arguments(current, regs, __entry->args);
32 ), 32 ),
33 33
34 TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", 34 TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)",
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 54a0347ca812..df27e499956a 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -149,7 +149,7 @@ static void populate_seccomp_data(struct seccomp_data *sd)
149 149
150 sd->nr = syscall_get_nr(task, regs); 150 sd->nr = syscall_get_nr(task, regs);
151 sd->arch = syscall_get_arch(); 151 sd->arch = syscall_get_arch();
152 syscall_get_arguments(task, regs, 0, 6, args); 152 syscall_get_arguments(task, regs, args);
153 sd->args[0] = args[0]; 153 sd->args[0] = args[0];
154 sd->args[1] = args[1]; 154 sd->args[1] = args[1];
155 sd->args[2] = args[2]; 155 sd->args[2] = args[2];
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index f93a56d2db27..fa8fbff736d6 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -314,6 +314,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
314 struct ring_buffer_event *event; 314 struct ring_buffer_event *event;
315 struct ring_buffer *buffer; 315 struct ring_buffer *buffer;
316 unsigned long irq_flags; 316 unsigned long irq_flags;
317 unsigned long args[6];
317 int pc; 318 int pc;
318 int syscall_nr; 319 int syscall_nr;
319 int size; 320 int size;
@@ -347,7 +348,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
347 348
348 entry = ring_buffer_event_data(event); 349 entry = ring_buffer_event_data(event);
349 entry->nr = syscall_nr; 350 entry->nr = syscall_nr;
350 syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); 351 syscall_get_arguments(current, regs, args);
352 memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args);
351 353
352 event_trigger_unlock_commit(trace_file, buffer, event, entry, 354 event_trigger_unlock_commit(trace_file, buffer, event, entry,
353 irq_flags, pc); 355 irq_flags, pc);
@@ -583,6 +585,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
583 struct syscall_metadata *sys_data; 585 struct syscall_metadata *sys_data;
584 struct syscall_trace_enter *rec; 586 struct syscall_trace_enter *rec;
585 struct hlist_head *head; 587 struct hlist_head *head;
588 unsigned long args[6];
586 bool valid_prog_array; 589 bool valid_prog_array;
587 int syscall_nr; 590 int syscall_nr;
588 int rctx; 591 int rctx;
@@ -613,8 +616,8 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
613 return; 616 return;
614 617
615 rec->nr = syscall_nr; 618 rec->nr = syscall_nr;
616 syscall_get_arguments(current, regs, 0, sys_data->nb_args, 619 syscall_get_arguments(current, regs, args);
617 (unsigned long *)&rec->args); 620 memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args);
618 621
619 if ((valid_prog_array && 622 if ((valid_prog_array &&
620 !perf_call_bpf_enter(sys_data->enter_event, regs, sys_data, rec)) || 623 !perf_call_bpf_enter(sys_data->enter_event, regs, sys_data, rec)) ||
diff --git a/lib/syscall.c b/lib/syscall.c
index 1a7077f20eae..fb328e7ccb08 100644
--- a/lib/syscall.c
+++ b/lib/syscall.c
@@ -5,16 +5,14 @@
5#include <linux/export.h> 5#include <linux/export.h>
6#include <asm/syscall.h> 6#include <asm/syscall.h>
7 7
8static int collect_syscall(struct task_struct *target, long *callno, 8static int collect_syscall(struct task_struct *target, struct syscall_info *info)
9 unsigned long args[6], unsigned int maxargs,
10 unsigned long *sp, unsigned long *pc)
11{ 9{
12 struct pt_regs *regs; 10 struct pt_regs *regs;
13 11
14 if (!try_get_task_stack(target)) { 12 if (!try_get_task_stack(target)) {
15 /* Task has no stack, so the task isn't in a syscall. */ 13 /* Task has no stack, so the task isn't in a syscall. */
16 *sp = *pc = 0; 14 memset(info, 0, sizeof(*info));
17 *callno = -1; 15 info->data.nr = -1;
18 return 0; 16 return 0;
19 } 17 }
20 18
@@ -24,12 +22,13 @@ static int collect_syscall(struct task_struct *target, long *callno,
24 return -EAGAIN; 22 return -EAGAIN;
25 } 23 }
26 24
27 *sp = user_stack_pointer(regs); 25 info->sp = user_stack_pointer(regs);
28 *pc = instruction_pointer(regs); 26 info->data.instruction_pointer = instruction_pointer(regs);
29 27
30 *callno = syscall_get_nr(target, regs); 28 info->data.nr = syscall_get_nr(target, regs);
31 if (*callno != -1L && maxargs > 0) 29 if (info->data.nr != -1L)
32 syscall_get_arguments(target, regs, 0, maxargs, args); 30 syscall_get_arguments(target, regs,
31 (unsigned long *)&info->data.args[0]);
33 32
34 put_task_stack(target); 33 put_task_stack(target);
35 return 0; 34 return 0;
@@ -38,41 +37,35 @@ static int collect_syscall(struct task_struct *target, long *callno,
38/** 37/**
39 * task_current_syscall - Discover what a blocked task is doing. 38 * task_current_syscall - Discover what a blocked task is doing.
40 * @target: thread to examine 39 * @target: thread to examine
41 * @callno: filled with system call number or -1 40 * @info: structure with the following fields:
42 * @args: filled with @maxargs system call arguments 41 * .sp - filled with user stack pointer
43 * @maxargs: number of elements in @args to fill 42 * .data.nr - filled with system call number or -1
44 * @sp: filled with user stack pointer 43 * .data.args - filled with @maxargs system call arguments
45 * @pc: filled with user PC 44 * .data.instruction_pointer - filled with user PC
46 * 45 *
47 * If @target is blocked in a system call, returns zero with *@callno 46 * If @target is blocked in a system call, returns zero with @info.data.nr
48 * set to the the call's number and @args filled in with its arguments. 47 * set to the the call's number and @info.data.args filled in with its
49 * Registers not used for system call arguments may not be available and 48 * arguments. Registers not used for system call arguments may not be available
50 * it is not kosher to use &struct user_regset calls while the system 49 * and it is not kosher to use &struct user_regset calls while the system
51 * call is still in progress. Note we may get this result if @target 50 * call is still in progress. Note we may get this result if @target
52 * has finished its system call but not yet returned to user mode, such 51 * has finished its system call but not yet returned to user mode, such
53 * as when it's stopped for signal handling or syscall exit tracing. 52 * as when it's stopped for signal handling or syscall exit tracing.
54 * 53 *
55 * If @target is blocked in the kernel during a fault or exception, 54 * If @target is blocked in the kernel during a fault or exception,
56 * returns zero with *@callno set to -1 and does not fill in @args. 55 * returns zero with *@info.data.nr set to -1 and does not fill in
57 * If so, it's now safe to examine @target using &struct user_regset 56 * @info.data.args. If so, it's now safe to examine @target using
58 * get() calls as long as we're sure @target won't return to user mode. 57 * &struct user_regset get() calls as long as we're sure @target won't return
58 * to user mode.
59 * 59 *
60 * Returns -%EAGAIN if @target does not remain blocked. 60 * Returns -%EAGAIN if @target does not remain blocked.
61 *
62 * Returns -%EINVAL if @maxargs is too large (maximum is six).
63 */ 61 */
64int task_current_syscall(struct task_struct *target, long *callno, 62int task_current_syscall(struct task_struct *target, struct syscall_info *info)
65 unsigned long args[6], unsigned int maxargs,
66 unsigned long *sp, unsigned long *pc)
67{ 63{
68 long state; 64 long state;
69 unsigned long ncsw; 65 unsigned long ncsw;
70 66
71 if (unlikely(maxargs > 6))
72 return -EINVAL;
73
74 if (target == current) 67 if (target == current)
75 return collect_syscall(target, callno, args, maxargs, sp, pc); 68 return collect_syscall(target, info);
76 69
77 state = target->state; 70 state = target->state;
78 if (unlikely(!state)) 71 if (unlikely(!state))
@@ -80,7 +73,7 @@ int task_current_syscall(struct task_struct *target, long *callno,
80 73
81 ncsw = wait_task_inactive(target, state); 74 ncsw = wait_task_inactive(target, state);
82 if (unlikely(!ncsw) || 75 if (unlikely(!ncsw) ||
83 unlikely(collect_syscall(target, callno, args, maxargs, sp, pc)) || 76 unlikely(collect_syscall(target, info)) ||
84 unlikely(wait_task_inactive(target, state) != ncsw)) 77 unlikely(wait_task_inactive(target, state) != ncsw))
85 return -EAGAIN; 78 return -EAGAIN;
86 79