Skip to content

Commit

Permalink
syscalls: Remove start and number from syscall_get_arguments() args
Browse files Browse the repository at this point in the history
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/[email protected]

Cc: Oleg Nesterov <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Dominik Brodowski <[email protected]>
Cc: Dave Martin <[email protected]>
Cc: "Dmitry V. Levin" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Acked-by: Paul Burton <[email protected]> # MIPS parts
Acked-by: Max Filippov <[email protected]> # For xtensa changes
Acked-by: Will Deacon <[email protected]> # For the arm64 bits
Reviewed-by: Thomas Gleixner <[email protected]> # for x86
Reviewed-by: Dmitry V. Levin <[email protected]>
Reported-by: Andy Lutomirski <[email protected]>
Signed-off-by: Steven Rostedt (VMware) <[email protected]>
  • Loading branch information
rostedt committed Apr 5, 2019
1 parent ed3bb00 commit b35f549
Show file tree
Hide file tree
Showing 29 changed files with 113 additions and 378 deletions.
7 changes: 3 additions & 4 deletions arch/arc/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
*/
static inline void
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);
inside_ptregs -= i;

BUG_ON((i + n) > 6);
unsigned int n = 6;
unsigned int i = 0;

while (n--) {
args[i++] = (*inside_ptregs);
Expand Down
23 changes: 3 additions & 20 deletions arch/arm/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
if (n == 0)
return;

if (i + n > SYSCALL_MAX_ARGS) {
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--;
}
args[0] = regs->ARM_ORIG_r0;
args++;

memcpy(args, &regs->ARM_r0 + i, n * sizeof(args[0]));
memcpy(args, &regs->ARM_r0 + 1, 5 * sizeof(args[0]));
}

static inline void syscall_set_arguments(struct task_struct *task,
Expand Down
22 changes: 3 additions & 19 deletions arch/arm64/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
if (n == 0)
return;

if (i + n > SYSCALL_MAX_ARGS) {
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--;
}
args[0] = regs->orig_x0;
args++;

memcpy(args, &regs->regs[i], n * sizeof(args[0]));
memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
}

static inline void syscall_set_arguments(struct task_struct *task,
Expand Down
41 changes: 8 additions & 33 deletions arch/c6x/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs, unsigned int i,
unsigned int n, unsigned long *args)
struct pt_regs *regs,
unsigned long *args)
{
switch (i) {
case 0:
if (!n--)
break;
*args++ = regs->a4;
case 1:
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();
}
*args++ = regs->a4;
*args++ = regs->b4;
*args++ = regs->a6;
*args++ = regs->b6;
*args++ = regs->a8;
*args = regs->b8;
}

static inline void syscall_set_arguments(struct task_struct *task,
Expand Down
14 changes: 4 additions & 10 deletions arch/csky/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,

static inline void
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);
if (i == 0) {
args[0] = regs->orig_a0;
args++;
n--;
} else {
i--;
}
memcpy(args, &regs->a1 + i, n * sizeof(args[0]));
args[0] = regs->orig_a0;
args++;
memcpy(args, &regs->a1, 5 * sizeof(args[0]));
}

static inline void
Expand Down
34 changes: 7 additions & 27 deletions arch/h8300/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,14 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)

static inline void
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);

while (n > 0) {
switch (i) {
case 0:
*args++ = regs->er1;
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--;
}
*args++ = regs->er1;
*args++ = regs->er2;
*args++ = regs->er3;
*args++ = regs->er4;
*args++ = regs->er5;
*args = regs->er6;
}


Expand Down
4 changes: 1 addition & 3 deletions arch/hexagon/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ static inline long syscall_get_nr(struct task_struct *task,

static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
BUG_ON(i + n > 6);
memcpy(args, &(&regs->r00)[i], n * sizeof(args[0]));
memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
}
#endif
5 changes: 1 addition & 4 deletions arch/ia64/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,9 @@ extern void ia64_syscall_get_set_arguments(struct task_struct *task,
unsigned long *args, int rw);
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
BUG_ON(i + n > 6);

ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
ia64_syscall_get_set_arguments(task, regs, 0, 6, args, 0);
}

static inline void syscall_set_arguments(struct task_struct *task,
Expand Down
4 changes: 3 additions & 1 deletion arch/microblaze/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
unsigned int i = 0;
unsigned int n = 6;

while (n--)
*args++ = microblaze_get_syscall_arg(regs, i++);
}
Expand Down
3 changes: 2 additions & 1 deletion arch/mips/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
unsigned int i = 0;
unsigned int n = 6;
int ret;

/* O32 ABI syscall() */
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)

sd.nr = syscall;
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++)
sd.args[i] = args[i];
sd.instruction_pointer = KSTK_EIP(current);
Expand Down
33 changes: 6 additions & 27 deletions arch/nds32/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
* @task: task of interest, must be blocked
* @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
*
* Fetches @n arguments to the system call starting with the @i'th argument
* (from 0 through 5). Argument @i is stored in @args[0], and so on.
* An arch inline version is probably optimal when @i and @n are constants.
* Fetches 6 arguments to the system call (from 0 through 5). The first
* argument is stored in @args[0], and so 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.
* 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
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)
return;
if (i + n > SYSCALL_MAX_ARGS) {
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]));
args[0] = regs->orig_r0;
args++;
memcpy(args, &regs->uregs[0] + 1, 5 * sizeof(args[0]));
}

/**
Expand Down
42 changes: 7 additions & 35 deletions arch/nios2/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct pt_regs *regs, unsigned int i, unsigned int n,
unsigned long *args)
struct pt_regs *regs, unsigned long *args)
{
BUG_ON(i + n > 6);

switch (i) {
case 0:
if (!n--)
break;
*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();
}
*args++ = regs->r4;
*args++ = regs->r5;
*args++ = regs->r6;
*args++ = regs->r7;
*args++ = regs->r8;
*args = regs->r9;
}

static inline void syscall_set_arguments(struct task_struct *task,
Expand Down
6 changes: 2 additions & 4 deletions arch/openrisc/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,

static inline void
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 + i], n * sizeof(args[0]));
memcpy(args, &regs->gpr[3], 6 * sizeof(args[0]));
}

static inline void
Expand Down
Loading

0 comments on commit b35f549

Please sign in to comment.