mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 17:41:44 +00:00
4c21b8fd8f
When userland uses syscall() to perform an indirect system call the actually system call that needs to be checked by the filter is on the first argument. The kernel code needs to handle this case by looking at the original syscall number in v0 and if it's NR_syscall, then it needs to examine the first argument to identify the real system call that will be executed. Similarly, we need to 'virtually' shift the syscall() arguments so the syscall_get_arguments() function can fetch the correct arguments for the indirect system call. Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Reviewed-by: James Hogan <james.hogan@imgtec.com> Reviewed-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6404/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
116 lines
3.0 KiB
C
116 lines
3.0 KiB
C
/*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle
|
|
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
|
*/
|
|
#ifndef _ASM_PTRACE_H
|
|
#define _ASM_PTRACE_H
|
|
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/linkage.h>
|
|
#include <linux/types.h>
|
|
#include <asm/isadep.h>
|
|
#include <uapi/asm/ptrace.h>
|
|
|
|
/*
|
|
* This struct defines the way the registers are stored on the stack during a
|
|
* system call/exception. As usual the registers k0/k1 aren't being saved.
|
|
*/
|
|
struct pt_regs {
|
|
#ifdef CONFIG_32BIT
|
|
/* Pad bytes for argument save space on the stack. */
|
|
unsigned long pad0[6];
|
|
#endif
|
|
|
|
/* Saved main processor registers. */
|
|
unsigned long regs[32];
|
|
|
|
/* Saved special registers. */
|
|
unsigned long cp0_status;
|
|
unsigned long hi;
|
|
unsigned long lo;
|
|
#ifdef CONFIG_CPU_HAS_SMARTMIPS
|
|
unsigned long acx;
|
|
#endif
|
|
unsigned long cp0_badvaddr;
|
|
unsigned long cp0_cause;
|
|
unsigned long cp0_epc;
|
|
#ifdef CONFIG_MIPS_MT_SMTC
|
|
unsigned long cp0_tcstatus;
|
|
#endif /* CONFIG_MIPS_MT_SMTC */
|
|
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
|
unsigned long long mpl[3]; /* MTM{0,1,2} */
|
|
unsigned long long mtp[3]; /* MTP{0,1,2} */
|
|
#endif
|
|
} __aligned(8);
|
|
|
|
struct task_struct;
|
|
|
|
extern int ptrace_getregs(struct task_struct *child, __s64 __user *data);
|
|
extern int ptrace_setregs(struct task_struct *child, __s64 __user *data);
|
|
|
|
extern int ptrace_getfpregs(struct task_struct *child, __u32 __user *data);
|
|
extern int ptrace_setfpregs(struct task_struct *child, __u32 __user *data);
|
|
|
|
extern int ptrace_get_watch_regs(struct task_struct *child,
|
|
struct pt_watch_regs __user *addr);
|
|
extern int ptrace_set_watch_regs(struct task_struct *child,
|
|
struct pt_watch_regs __user *addr);
|
|
|
|
/*
|
|
* Does the process account for user or for system time?
|
|
*/
|
|
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
|
|
|
|
static inline int is_syscall_success(struct pt_regs *regs)
|
|
{
|
|
return !regs->regs[7];
|
|
}
|
|
|
|
static inline long regs_return_value(struct pt_regs *regs)
|
|
{
|
|
if (is_syscall_success(regs))
|
|
return regs->regs[2];
|
|
else
|
|
return -regs->regs[2];
|
|
}
|
|
|
|
#define instruction_pointer(regs) ((regs)->cp0_epc)
|
|
#define profile_pc(regs) instruction_pointer(regs)
|
|
|
|
extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall);
|
|
extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
|
|
|
|
extern void die(const char *, struct pt_regs *) __noreturn;
|
|
|
|
static inline void die_if_kernel(const char *str, struct pt_regs *regs)
|
|
{
|
|
if (unlikely(!user_mode(regs)))
|
|
die(str, regs);
|
|
}
|
|
|
|
#define current_pt_regs() \
|
|
({ \
|
|
unsigned long sp = (unsigned long)__builtin_frame_address(0); \
|
|
(struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1; \
|
|
})
|
|
|
|
/* Helpers for working with the user stack pointer */
|
|
|
|
static inline unsigned long user_stack_pointer(struct pt_regs *regs)
|
|
{
|
|
return regs->regs[29];
|
|
}
|
|
|
|
static inline void user_stack_pointer_set(struct pt_regs *regs,
|
|
unsigned long val)
|
|
{
|
|
regs->regs[29] = val;
|
|
}
|
|
|
|
#endif /* _ASM_PTRACE_H */
|