162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle
762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#ifndef _ASM_PTRACE_H
1062306a36Sopenharmony_ci#define _ASM_PTRACE_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/compiler.h>
1462306a36Sopenharmony_ci#include <linux/linkage.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <asm/isadep.h>
1762306a36Sopenharmony_ci#include <asm/page.h>
1862306a36Sopenharmony_ci#include <asm/thread_info.h>
1962306a36Sopenharmony_ci#include <uapi/asm/ptrace.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * This struct defines the way the registers are stored on the stack during a
2362306a36Sopenharmony_ci * system call/exception. As usual the registers k0/k1 aren't being saved.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * If you add a register here, also add it to regoffset_table[] in
2662306a36Sopenharmony_ci * arch/mips/kernel/ptrace.c.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_cistruct pt_regs {
2962306a36Sopenharmony_ci#ifdef CONFIG_32BIT
3062306a36Sopenharmony_ci	/* Pad bytes for argument save space on the stack. */
3162306a36Sopenharmony_ci	unsigned long pad0[8];
3262306a36Sopenharmony_ci#endif
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* Saved main processor registers. */
3562306a36Sopenharmony_ci	unsigned long regs[32];
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* Saved special registers. */
3862306a36Sopenharmony_ci	unsigned long cp0_status;
3962306a36Sopenharmony_ci	unsigned long hi;
4062306a36Sopenharmony_ci	unsigned long lo;
4162306a36Sopenharmony_ci#ifdef CONFIG_CPU_HAS_SMARTMIPS
4262306a36Sopenharmony_ci	unsigned long acx;
4362306a36Sopenharmony_ci#endif
4462306a36Sopenharmony_ci	unsigned long cp0_badvaddr;
4562306a36Sopenharmony_ci	unsigned long cp0_cause;
4662306a36Sopenharmony_ci	unsigned long cp0_epc;
4762306a36Sopenharmony_ci#ifdef CONFIG_CPU_CAVIUM_OCTEON
4862306a36Sopenharmony_ci	unsigned long long mpl[6];        /* MTM{0-5} */
4962306a36Sopenharmony_ci	unsigned long long mtp[6];        /* MTP{0-5} */
5062306a36Sopenharmony_ci#endif
5162306a36Sopenharmony_ci	unsigned long __last[0];
5262306a36Sopenharmony_ci} __aligned(8);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return regs->regs[29];
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic inline void instruction_pointer_set(struct pt_regs *regs,
6062306a36Sopenharmony_ci                                           unsigned long val)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	regs->cp0_epc = val;
6362306a36Sopenharmony_ci	regs->cp0_cause &= ~CAUSEF_BD;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Query offset/name of register from its name/offset */
6762306a36Sopenharmony_ciextern int regs_query_register_offset(const char *name);
6862306a36Sopenharmony_ci#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last))
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/**
7162306a36Sopenharmony_ci * regs_get_register() - get register value from its offset
7262306a36Sopenharmony_ci * @regs:       pt_regs from which register value is gotten.
7362306a36Sopenharmony_ci * @offset:     offset number of the register.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * regs_get_register returns the value of a register. The @offset is the
7662306a36Sopenharmony_ci * offset of the register in struct pt_regs address which specified by @regs.
7762306a36Sopenharmony_ci * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_cistatic inline unsigned long regs_get_register(struct pt_regs *regs,
8062306a36Sopenharmony_ci                                              unsigned int offset)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	if (unlikely(offset > MAX_REG_OFFSET))
8362306a36Sopenharmony_ci		return 0;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return *(unsigned long *)((unsigned long)regs + offset);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * regs_within_kernel_stack() - check the address in the stack
9062306a36Sopenharmony_ci * @regs:       pt_regs which contains kernel stack pointer.
9162306a36Sopenharmony_ci * @addr:       address which is checked.
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
9462306a36Sopenharmony_ci * If @addr is within the kernel stack, it returns true. If not, returns false.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic inline int regs_within_kernel_stack(struct pt_regs *regs,
9762306a36Sopenharmony_ci                                           unsigned long addr)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	return ((addr & ~(THREAD_SIZE - 1))  ==
10062306a36Sopenharmony_ci		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * regs_get_kernel_stack_nth() - get Nth entry of the stack
10562306a36Sopenharmony_ci * @regs:       pt_regs which contains kernel stack pointer.
10662306a36Sopenharmony_ci * @n:          stack entry number.
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
10962306a36Sopenharmony_ci * is specified by @regs. If the @n th entry is NOT in the kernel stack,
11062306a36Sopenharmony_ci * this returns 0.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistatic inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
11362306a36Sopenharmony_ci                                                      unsigned int n)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	addr += n;
11862306a36Sopenharmony_ci	if (regs_within_kernel_stack(regs, (unsigned long)addr))
11962306a36Sopenharmony_ci		return *addr;
12062306a36Sopenharmony_ci	else
12162306a36Sopenharmony_ci		return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistruct task_struct;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciextern int ptrace_getregs(struct task_struct *child,
12762306a36Sopenharmony_ci	struct user_pt_regs __user *data);
12862306a36Sopenharmony_ciextern int ptrace_setregs(struct task_struct *child,
12962306a36Sopenharmony_ci	struct user_pt_regs __user *data);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciextern int ptrace_getfpregs(struct task_struct *child, __u32 __user *data);
13262306a36Sopenharmony_ciextern int ptrace_setfpregs(struct task_struct *child, __u32 __user *data);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciextern int ptrace_get_watch_regs(struct task_struct *child,
13562306a36Sopenharmony_ci	struct pt_watch_regs __user *addr);
13662306a36Sopenharmony_ciextern int ptrace_set_watch_regs(struct task_struct *child,
13762306a36Sopenharmony_ci	struct pt_watch_regs __user *addr);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/*
14062306a36Sopenharmony_ci * Does the process account for user or for system time?
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_ci#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic inline int is_syscall_success(struct pt_regs *regs)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	return !regs->regs[7];
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline long regs_return_value(struct pt_regs *regs)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	if (is_syscall_success(regs) || !user_mode(regs))
15262306a36Sopenharmony_ci		return regs->regs[2];
15362306a36Sopenharmony_ci	else
15462306a36Sopenharmony_ci		return -regs->regs[2];
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define instruction_pointer(regs) ((regs)->cp0_epc)
15862306a36Sopenharmony_ciextern unsigned long exception_ip(struct pt_regs *regs);
15962306a36Sopenharmony_ci#define exception_ip(regs) exception_ip(regs)
16062306a36Sopenharmony_ci#define profile_pc(regs) instruction_pointer(regs)
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciextern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall);
16362306a36Sopenharmony_ciextern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciextern void die(const char *, struct pt_regs *) __noreturn;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic inline void die_if_kernel(const char *str, struct pt_regs *regs)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	if (unlikely(!user_mode(regs)))
17062306a36Sopenharmony_ci		die(str, regs);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define current_pt_regs()						\
17462306a36Sopenharmony_ci({									\
17562306a36Sopenharmony_ci	unsigned long sp = (unsigned long)__builtin_frame_address(0);	\
17662306a36Sopenharmony_ci	(struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1;	\
17762306a36Sopenharmony_ci})
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* Helpers for working with the user stack pointer */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic inline unsigned long user_stack_pointer(struct pt_regs *regs)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	return regs->regs[29];
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic inline void user_stack_pointer_set(struct pt_regs *regs,
18762306a36Sopenharmony_ci	unsigned long val)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	regs->regs[29] = val;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#endif /* _ASM_PTRACE_H */
193