syscalls: Remove start and number from syscall_get_arguments() args

At Linux Plumbers, Andy Lutomirski approached me and pointed out that the
function call syscall_get_arguments() implemented in x86 was horribly
written and not optimized for the standard case of passing in 0 and 6 for
the starting index and the number of system calls to get. When looking at
all the users of this function, I discovered that all instances pass in only
0 and 6 for these arguments. Instead of having this function handle
different cases that are never used, simply rewrite it to return the first 6
arguments of a system call.

This should help out the performance of tracing system calls by ptrace,
ftrace and perf.

Link: http://lkml.kernel.org/r/20161107213233.754809394@goodmis.org

Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Dave Martin <dave.martin@arm.com>
Cc: "Dmitry V. Levin" <ldv@altlinux.org>
Cc: x86@kernel.org
Cc: linux-snps-arc@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-c6x-dev@linux-c6x.org
Cc: uclinux-h8-devel@lists.sourceforge.jp
Cc: linux-hexagon@vger.kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linux-mips@vger.kernel.org
Cc: nios2-dev@lists.rocketboards.org
Cc: openrisc@lists.librecores.org
Cc: linux-parisc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-riscv@lists.infradead.org
Cc: linux-s390@vger.kernel.org
Cc: linux-sh@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Cc: linux-um@lists.infradead.org
Cc: linux-xtensa@linux-xtensa.org
Cc: linux-arch@vger.kernel.org
Acked-by: Paul Burton <paul.burton@mips.com> # MIPS parts
Acked-by: Max Filippov <jcmvbkbc@gmail.com> # For xtensa changes
Acked-by: Will Deacon <will.deacon@arm.com> # For the arm64 bits
Reviewed-by: Thomas Gleixner <tglx@linutronix.de> # for x86
Reviewed-by: Dmitry V. Levin <ldv@altlinux.org>
Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Steven Rostedt (Red Hat) 2016-11-07 16:26:37 -05:00 committed by Steven Rostedt (VMware)
parent ed3bb00702
commit b35f549df1
29 changed files with 113 additions and 378 deletions

View File

@ -55,12 +55,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
*/ */
static inline void static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args) unsigned long *args)
{ {
unsigned long *inside_ptregs = &(regs->r0); unsigned long *inside_ptregs = &(regs->r0);
inside_ptregs -= i; unsigned int n = 6;
unsigned int i = 0;
BUG_ON((i + n) > 6);
while (n--) { while (n--) {
args[i++] = (*inside_ptregs); args[i++] = (*inside_ptregs);

View File

@ -55,29 +55,12 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
if (n == 0) args[0] = regs->ARM_ORIG_r0;
return; args++;
if (i + n > SYSCALL_MAX_ARGS) { memcpy(args, &regs->ARM_r0 + 1, 5 * sizeof(args[0]));
unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
pr_warn("%s called with max args %d, handling only %d\n",
__func__, i + n, SYSCALL_MAX_ARGS);
memset(args_bad, 0, n_bad * sizeof(args[0]));
n = SYSCALL_MAX_ARGS - i;
}
if (i == 0) {
args[0] = regs->ARM_ORIG_r0;
args++;
i++;
n--;
}
memcpy(args, &regs->ARM_r0 + i, n * sizeof(args[0]));
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -65,28 +65,12 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
if (n == 0) args[0] = regs->orig_x0;
return; args++;
if (i + n > SYSCALL_MAX_ARGS) { memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
pr_warning("%s called with max args %d, handling only %d\n",
__func__, i + n, SYSCALL_MAX_ARGS);
memset(args_bad, 0, n_bad * sizeof(args[0]));
}
if (i == 0) {
args[0] = regs->orig_x0;
args++;
i++;
n--;
}
memcpy(args, &regs->regs[i], n * sizeof(args[0]));
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -46,40 +46,15 @@ static inline void syscall_set_return_value(struct task_struct *task,
} }
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, unsigned int i, struct pt_regs *regs,
unsigned int n, unsigned long *args) unsigned long *args)
{ {
switch (i) { *args++ = regs->a4;
case 0: *args++ = regs->b4;
if (!n--) *args++ = regs->a6;
break; *args++ = regs->b6;
*args++ = regs->a4; *args++ = regs->a8;
case 1: *args = regs->b8;
if (!n--)
break;
*args++ = regs->b4;
case 2:
if (!n--)
break;
*args++ = regs->a6;
case 3:
if (!n--)
break;
*args++ = regs->b6;
case 4:
if (!n--)
break;
*args++ = regs->a8;
case 5:
if (!n--)
break;
*args++ = regs->b8;
case 6:
if (!n--)
break;
default:
BUG();
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -43,17 +43,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
static inline void static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); args[0] = regs->orig_a0;
if (i == 0) { args++;
args[0] = regs->orig_a0; memcpy(args, &regs->a1, 5 * sizeof(args[0]));
args++;
n--;
} else {
i--;
}
memcpy(args, &regs->a1 + i, n * sizeof(args[0]));
} }
static inline void static inline void

View File

@ -17,34 +17,14 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
static inline void static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); *args++ = regs->er1;
*args++ = regs->er2;
while (n > 0) { *args++ = regs->er3;
switch (i) { *args++ = regs->er4;
case 0: *args++ = regs->er5;
*args++ = regs->er1; *args = regs->er6;
break;
case 1:
*args++ = regs->er2;
break;
case 2:
*args++ = regs->er3;
break;
case 3:
*args++ = regs->er4;
break;
case 4:
*args++ = regs->er5;
break;
case 5:
*args++ = regs->er6;
break;
}
i++;
n--;
}
} }

View File

@ -37,10 +37,8 @@ static inline long syscall_get_nr(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
memcpy(args, &(&regs->r00)[i], n * sizeof(args[0]));
} }
#endif #endif

View File

@ -63,12 +63,9 @@ extern void ia64_syscall_get_set_arguments(struct task_struct *task,
unsigned long *args, int rw); unsigned long *args, int rw);
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); ia64_syscall_get_set_arguments(task, regs, 0, 6, args, 0);
ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -82,9 +82,11 @@ static inline void microblaze_set_syscall_arg(struct pt_regs *regs,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
unsigned int i = 0;
unsigned int n = 6;
while (n--) while (n--)
*args++ = microblaze_get_syscall_arg(regs, i++); *args++ = microblaze_get_syscall_arg(regs, i++);
} }

View File

@ -116,9 +116,10 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
unsigned int i = 0;
unsigned int n = 6;
int ret; int ret;
/* O32 ABI syscall() */ /* O32 ABI syscall() */

View File

@ -1419,7 +1419,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
sd.nr = syscall; sd.nr = syscall;
sd.arch = syscall_get_arch(); sd.arch = syscall_get_arch();
syscall_get_arguments(current, regs, 0, 6, args); syscall_get_arguments(current, regs, args);
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
sd.args[i] = args[i]; sd.args[i] = args[i];
sd.instruction_pointer = KSTK_EIP(current); sd.instruction_pointer = KSTK_EIP(current);

View File

@ -108,42 +108,21 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
* syscall_get_arguments - extract system call parameter values * syscall_get_arguments - extract system call parameter values
* @task: task of interest, must be blocked * @task: task of interest, must be blocked
* @regs: task_pt_regs() of @task * @regs: task_pt_regs() of @task
* @i: argument index [0,5]
* @n: number of arguments; n+i must be [1,6].
* @args: array filled with argument values * @args: array filled with argument values
* *
* Fetches @n arguments to the system call starting with the @i'th argument * Fetches 6 arguments to the system call (from 0 through 5). The first
* (from 0 through 5). Argument @i is stored in @args[0], and so on. * argument is stored in @args[0], and so on.
* An arch inline version is probably optimal when @i and @n are constants.
* *
* It's only valid to call this when @task is stopped for tracing on * It's only valid to call this when @task is stopped for tracing on
* entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
* It's invalid to call this with @i + @n > 6; we only support system calls
* taking up to 6 arguments.
*/ */
#define SYSCALL_MAX_ARGS 6 #define SYSCALL_MAX_ARGS 6
void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args) unsigned long *args)
{ {
if (n == 0) args[0] = regs->orig_r0;
return; args++;
if (i + n > SYSCALL_MAX_ARGS) { memcpy(args, &regs->uregs[0] + 1, 5 * sizeof(args[0]));
unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
pr_warning("%s called with max args %d, handling only %d\n",
__func__, i + n, SYSCALL_MAX_ARGS);
memset(args_bad, 0, n_bad * sizeof(args[0]));
memset(args_bad, 0, n_bad * sizeof(args[0]));
}
if (i == 0) {
args[0] = regs->orig_r0;
args++;
i++;
n--;
}
memcpy(args, &regs->uregs[0] + i, n * sizeof(args[0]));
} }
/** /**

View File

@ -58,42 +58,14 @@ static inline void syscall_set_return_value(struct task_struct *task,
} }
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, unsigned int i, unsigned int n, struct pt_regs *regs, unsigned long *args)
unsigned long *args)
{ {
BUG_ON(i + n > 6); *args++ = regs->r4;
*args++ = regs->r5;
switch (i) { *args++ = regs->r6;
case 0: *args++ = regs->r7;
if (!n--) *args++ = regs->r8;
break; *args = regs->r9;
*args++ = regs->r4;
case 1:
if (!n--)
break;
*args++ = regs->r5;
case 2:
if (!n--)
break;
*args++ = regs->r6;
case 3:
if (!n--)
break;
*args++ = regs->r7;
case 4:
if (!n--)
break;
*args++ = regs->r8;
case 5:
if (!n--)
break;
*args++ = regs->r9;
case 6:
if (!n--)
break;
default:
BUG();
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -56,11 +56,9 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
static inline void static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); memcpy(args, &regs->gpr[3], 6 * sizeof(args[0]));
memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
} }
static inline void static inline void

View File

@ -18,29 +18,15 @@ static inline long syscall_get_nr(struct task_struct *tsk,
} }
static inline void syscall_get_arguments(struct task_struct *tsk, static inline void syscall_get_arguments(struct task_struct *tsk,
struct pt_regs *regs, unsigned int i, struct pt_regs *regs,
unsigned int n, unsigned long *args) unsigned long *args)
{ {
BUG_ON(i); args[5] = regs->gr[21];
args[4] = regs->gr[22];
switch (n) { args[3] = regs->gr[23];
case 6: args[2] = regs->gr[24];
args[5] = regs->gr[21]; args[1] = regs->gr[25];
case 5: args[0] = regs->gr[26];
args[4] = regs->gr[22];
case 4:
args[3] = regs->gr[23];
case 3:
args[2] = regs->gr[24];
case 2:
args[1] = regs->gr[25];
case 1:
args[0] = regs->gr[26];
case 0:
break;
default:
BUG();
}
} }
static inline long syscall_get_return_value(struct task_struct *task, static inline long syscall_get_return_value(struct task_struct *task,

View File

@ -65,22 +65,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
unsigned long val, mask = -1UL; unsigned long val, mask = -1UL;
unsigned int n = 6;
BUG_ON(i + n > 6);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
if (test_tsk_thread_flag(task, TIF_32BIT)) if (test_tsk_thread_flag(task, TIF_32BIT))
mask = 0xffffffff; mask = 0xffffffff;
#endif #endif
while (n--) { while (n--) {
if (n == 0 && i == 0) if (n == 0)
val = regs->orig_gpr3; val = regs->orig_gpr3;
else else
val = regs->gpr[3 + i + n]; val = regs->gpr[3 + n];
args[n] = val & mask; args[n] = val & mask;
} }

View File

@ -72,18 +72,11 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); args[0] = regs->orig_a0;
if (i == 0) { args++;
args[0] = regs->orig_a0; memcpy(args, &regs->a1, 5 * sizeof(args[0]));
args++;
n--;
} else {
i--;
}
memcpy(args, &regs->a1 + i, n * sizeof(args[0]));
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -56,27 +56,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
unsigned long mask = -1UL; unsigned long mask = -1UL;
unsigned int n = 6;
/*
* No arguments for this syscall, there's nothing to do.
*/
if (!n)
return;
BUG_ON(i + n > 6);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
if (test_tsk_thread_flag(task, TIF_31BIT)) if (test_tsk_thread_flag(task, TIF_31BIT))
mask = 0xffffffff; mask = 0xffffffff;
#endif #endif
while (n-- > 0) while (n-- > 0)
if (i + n > 0) if (n > 0)
args[n] = regs->gprs[2 + i + n] & mask; args[n] = regs->gprs[2 + n] & mask;
if (i == 0)
args[0] = regs->orig_gpr2 & mask; args[0] = regs->orig_gpr2 & mask;
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -48,30 +48,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
/*
* Do this simply for now. If we need to start supporting
* fetching arguments from arbitrary indices, this will need some
* extra logic. Presently there are no in-tree users that depend
* on this behaviour.
*/
BUG_ON(i);
/* Argument pattern is: R4, R5, R6, R7, R0, R1 */ /* Argument pattern is: R4, R5, R6, R7, R0, R1 */
switch (n) { args[5] = regs->regs[1];
case 6: args[5] = regs->regs[1]; args[4] = regs->regs[0];
case 5: args[4] = regs->regs[0]; args[3] = regs->regs[7];
case 4: args[3] = regs->regs[7]; args[2] = regs->regs[6];
case 3: args[2] = regs->regs[6]; args[1] = regs->regs[5];
case 2: args[1] = regs->regs[5]; args[0] = regs->regs[4];
case 1: args[0] = regs->regs[4];
case 0:
break;
default:
BUG();
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -47,11 +47,9 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); memcpy(args, &regs->regs[2], 6 * sizeof(args[0]));
memcpy(args, &regs->regs[2 + i], n * sizeof(args[0]));
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -96,11 +96,11 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
int zero_extend = 0; int zero_extend = 0;
unsigned int j; unsigned int j;
unsigned int n = 6;
#ifdef CONFIG_SPARC64 #ifdef CONFIG_SPARC64
if (test_tsk_thread_flag(task, TIF_32BIT)) if (test_tsk_thread_flag(task, TIF_32BIT))
@ -108,7 +108,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
#endif #endif
for (j = 0; j < n; j++) { for (j = 0; j < n; j++) {
unsigned long val = regs->u_regs[UREG_I0 + i + j]; unsigned long val = regs->u_regs[UREG_I0 + j];
if (zero_extend) if (zero_extend)
args[j] = (u32) val; args[j] = (u32) val;

View File

@ -53,43 +53,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
const struct uml_pt_regs *r = &regs->regs; const struct uml_pt_regs *r = &regs->regs;
switch (i) { *args++ = UPT_SYSCALL_ARG1(r);
case 0: *args++ = UPT_SYSCALL_ARG2(r);
if (!n--) *args++ = UPT_SYSCALL_ARG3(r);
break; *args++ = UPT_SYSCALL_ARG4(r);
*args++ = UPT_SYSCALL_ARG1(r); *args++ = UPT_SYSCALL_ARG5(r);
case 1: *args = UPT_SYSCALL_ARG6(r);
if (!n--)
break;
*args++ = UPT_SYSCALL_ARG2(r);
case 2:
if (!n--)
break;
*args++ = UPT_SYSCALL_ARG3(r);
case 3:
if (!n--)
break;
*args++ = UPT_SYSCALL_ARG4(r);
case 4:
if (!n--)
break;
*args++ = UPT_SYSCALL_ARG5(r);
case 5:
if (!n--)
break;
*args++ = UPT_SYSCALL_ARG6(r);
case 6:
if (!n--)
break;
default:
BUG();
break;
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -91,11 +91,9 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
BUG_ON(i + n > 6); memcpy(args, &regs->bx, 6 * sizeof(args[0]));
memcpy(args, &regs->bx + i, n * sizeof(args[0]));
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,
@ -116,63 +114,26 @@ static inline int syscall_get_arch(void)
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
# ifdef CONFIG_IA32_EMULATION # ifdef CONFIG_IA32_EMULATION
if (task->thread_info.status & TS_COMPAT) if (task->thread_info.status & TS_COMPAT) {
switch (i) { *args++ = regs->bx;
case 0: *args++ = regs->cx;
if (!n--) break; *args++ = regs->dx;
*args++ = regs->bx; *args++ = regs->si;
case 1: *args++ = regs->di;
if (!n--) break; *args = regs->bp;
*args++ = regs->cx; } else
case 2:
if (!n--) break;
*args++ = regs->dx;
case 3:
if (!n--) break;
*args++ = regs->si;
case 4:
if (!n--) break;
*args++ = regs->di;
case 5:
if (!n--) break;
*args++ = regs->bp;
case 6:
if (!n--) break;
default:
BUG();
break;
}
else
# endif # endif
switch (i) { {
case 0: *args++ = regs->di;
if (!n--) break; *args++ = regs->si;
*args++ = regs->di; *args++ = regs->dx;
case 1: *args++ = regs->r10;
if (!n--) break; *args++ = regs->r8;
*args++ = regs->si; *args = regs->r9;
case 2: }
if (!n--) break;
*args++ = regs->dx;
case 3:
if (!n--) break;
*args++ = regs->r10;
case 4:
if (!n--) break;
*args++ = regs->r8;
case 5:
if (!n--) break;
*args++ = regs->r9;
case 6:
if (!n--) break;
default:
BUG();
break;
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -59,23 +59,13 @@ static inline void syscall_set_return_value(struct task_struct *task,
static inline void syscall_get_arguments(struct task_struct *task, static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args) unsigned long *args)
{ {
static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS;
unsigned int j; unsigned int i;
if (n == 0) for (i = 0; i < 6; ++i)
return; args[i] = regs->areg[reg[i]];
WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS);
for (j = 0; j < n; ++j) {
if (i + j < SYSCALL_MAX_ARGS)
args[j] = regs->areg[reg[i + j]];
else
args[j] = 0;
}
} }
static inline void syscall_set_arguments(struct task_struct *task, static inline void syscall_set_arguments(struct task_struct *task,

View File

@ -105,21 +105,16 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
* syscall_get_arguments - extract system call parameter values * syscall_get_arguments - extract system call parameter values
* @task: task of interest, must be blocked * @task: task of interest, must be blocked
* @regs: task_pt_regs() of @task * @regs: task_pt_regs() of @task
* @i: argument index [0,5]
* @n: number of arguments; n+i must be [1,6].
* @args: array filled with argument values * @args: array filled with argument values
* *
* Fetches @n arguments to the system call starting with the @i'th argument * Fetches 6 arguments to the system call. First argument is stored in
* (from 0 through 5). Argument @i is stored in @args[0], and so on. * @args[0], and so on.
* An arch inline version is probably optimal when @i and @n are constants.
* *
* It's only valid to call this when @task is stopped for tracing on * It's only valid to call this when @task is stopped for tracing on
* entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
* It's invalid to call this with @i + @n > 6; we only support system calls
* taking up to 6 arguments.
*/ */
void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args); unsigned long *args);
/** /**
* syscall_set_arguments - change system call parameter value * syscall_set_arguments - change system call parameter value

View File

@ -28,7 +28,7 @@ TRACE_EVENT_FN(sys_enter,
TP_fast_assign( TP_fast_assign(
__entry->id = id; __entry->id = id;
syscall_get_arguments(current, regs, 0, 6, __entry->args); syscall_get_arguments(current, regs, __entry->args);
), ),
TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)",

View File

@ -149,7 +149,7 @@ static void populate_seccomp_data(struct seccomp_data *sd)
sd->nr = syscall_get_nr(task, regs); sd->nr = syscall_get_nr(task, regs);
sd->arch = syscall_get_arch(); sd->arch = syscall_get_arch();
syscall_get_arguments(task, regs, 0, 6, args); syscall_get_arguments(task, regs, args);
sd->args[0] = args[0]; sd->args[0] = args[0];
sd->args[1] = args[1]; sd->args[1] = args[1];
sd->args[2] = args[2]; sd->args[2] = args[2];

View File

@ -348,7 +348,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
entry = ring_buffer_event_data(event); entry = ring_buffer_event_data(event);
entry->nr = syscall_nr; entry->nr = syscall_nr;
syscall_get_arguments(current, regs, 0, 6, args); syscall_get_arguments(current, regs, args);
memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args); memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args);
event_trigger_unlock_commit(trace_file, buffer, event, entry, event_trigger_unlock_commit(trace_file, buffer, event, entry,
@ -616,7 +616,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
return; return;
rec->nr = syscall_nr; rec->nr = syscall_nr;
syscall_get_arguments(current, regs, 0, 6, args); syscall_get_arguments(current, regs, args);
memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args); memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args);
if ((valid_prog_array && if ((valid_prog_array &&

View File

@ -27,7 +27,7 @@ static int collect_syscall(struct task_struct *target, struct syscall_info *info
info->data.nr = syscall_get_nr(target, regs); info->data.nr = syscall_get_nr(target, regs);
if (info->data.nr != -1L) if (info->data.nr != -1L)
syscall_get_arguments(target, regs, 0, 6, syscall_get_arguments(target, regs,
(unsigned long *)&info->data.args[0]); (unsigned long *)&info->data.args[0]);
put_task_stack(target); put_task_stack(target);