diff options
Diffstat (limited to 'arch/mips/include/asm/ptrace.h')
| -rw-r--r-- | arch/mips/include/asm/ptrace.h | 80 | 
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index ffc320389f40..f6fc6aac5496 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -14,11 +14,16 @@  #include <linux/linkage.h>  #include <linux/types.h>  #include <asm/isadep.h> +#include <asm/page.h> +#include <asm/thread_info.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. + * + * If you add a register here, also add it to regoffset_table[] in + * arch/mips/kernel/ptrace.c.   */  struct pt_regs {  #ifdef CONFIG_32BIT @@ -43,8 +48,83 @@ struct pt_regs {  	unsigned long long mpl[6];        /* MTM{0-5} */  	unsigned long long mtp[6];        /* MTP{0-5} */  #endif +	unsigned long __last[0];  } __aligned(8); +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ +	return regs->regs[31]; +} + +/* + * Don't use asm-generic/ptrace.h it defines FP accessors that don't make + * sense on MIPS.  We rather want an error if they get invoked. + */ + +static inline void instruction_pointer_set(struct pt_regs *regs, +                                           unsigned long val) +{ +	regs->cp0_epc = val; +} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) + +/** + * regs_get_register() - get register value from its offset + * @regs:       pt_regs from which register value is gotten. + * @offset:     offset number of the register. + * + * regs_get_register returns the value of a register. The @offset is the + * offset of the register in struct pt_regs address which specified by @regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, +                                              unsigned int offset) +{ +	if (unlikely(offset > MAX_REG_OFFSET)) +		return 0; + +	return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs:       pt_regs which contains kernel stack pointer. + * @addr:       address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static inline int regs_within_kernel_stack(struct pt_regs *regs, +                                           unsigned long addr) +{ +	return ((addr & ~(THREAD_SIZE - 1))  == +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs:       pt_regs which contains kernel stack pointer. + * @n:          stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, +                                                      unsigned int n) +{ +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + +	addr += n; +	if (regs_within_kernel_stack(regs, (unsigned long)addr)) +		return *addr; +	else +		return 0; +} +  struct task_struct;  extern int ptrace_getregs(struct task_struct *child,  |