diff options
Diffstat (limited to 'arch/riscv/include/asm/ptrace.h')
| -rw-r--r-- | arch/riscv/include/asm/ptrace.h | 142 |
1 files changed, 102 insertions, 40 deletions
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index d35ec2f41381..addc8188152f 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -1,14 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Regents of the University of California - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _ASM_RISCV_PTRACE_H @@ -16,11 +8,12 @@ #include <uapi/asm/ptrace.h> #include <asm/csr.h> +#include <linux/compiler.h> -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct pt_regs { - unsigned long sepc; + unsigned long epc; unsigned long ra; unsigned long sp; unsigned long gp; @@ -30,14 +23,16 @@ struct pt_regs { unsigned long t2; unsigned long s0; unsigned long s1; - unsigned long a0; - unsigned long a1; - unsigned long a2; - unsigned long a3; - unsigned long a4; - unsigned long a5; - unsigned long a6; - unsigned long a7; + struct_group(a_regs, + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + ); unsigned long s2; unsigned long s3; unsigned long s4; @@ -52,65 +47,66 @@ struct pt_regs { unsigned long t4; unsigned long t5; unsigned long t6; - /* Supervisor CSRs */ - unsigned long sstatus; - unsigned long sbadaddr; - unsigned long scause; + /* Supervisor/Machine CSRs */ + unsigned long status; + unsigned long badaddr; + unsigned long cause; /* a0 value before the syscall */ unsigned long orig_a0; }; +#define PTRACE_SYSEMU 0x1f +#define PTRACE_SYSEMU_SINGLESTEP 0x20 + #ifdef CONFIG_64BIT #define REG_FMT "%016lx" #else #define REG_FMT "%08lx" #endif -#define user_mode(regs) (((regs)->sstatus & SR_SPP) == 0) +#define user_mode(regs) (((regs)->status & SR_PP) == 0) +#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0) /* Helpers for working with the instruction pointer */ -#define GET_IP(regs) ((regs)->sepc) -#define SET_IP(regs, val) (GET_IP(regs) = (val)) - static inline unsigned long instruction_pointer(struct pt_regs *regs) { - return GET_IP(regs); + return regs->epc; } static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long val) { - SET_IP(regs, val); + regs->epc = val; } #define profile_pc(regs) instruction_pointer(regs) /* Helpers for working with the user stack pointer */ -#define GET_USP(regs) ((regs)->sp) -#define SET_USP(regs, val) (GET_USP(regs) = (val)) - static inline unsigned long user_stack_pointer(struct pt_regs *regs) { - return GET_USP(regs); + return regs->sp; } static inline void user_stack_pointer_set(struct pt_regs *regs, unsigned long val) { - SET_USP(regs, val); + regs->sp = val; } -/* Helpers for working with the frame pointer */ -#define GET_FP(regs) ((regs)->s0) -#define SET_FP(regs, val) (GET_FP(regs) = (val)) +/* Valid only for Kernel mode traps. */ +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->sp; +} +/* Helpers for working with the frame pointer */ static inline unsigned long frame_pointer(struct pt_regs *regs) { - return GET_FP(regs); + return regs->s0; } static inline void frame_pointer_set(struct pt_regs *regs, unsigned long val) { - SET_FP(regs, val); + regs->s0 = val; } static inline unsigned long regs_return_value(struct pt_regs *regs) @@ -118,6 +114,72 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->a0; } -#endif /* __ASSEMBLY__ */ +static inline void regs_set_return_value(struct pt_regs *regs, + unsigned long val) +{ + regs->a0 = val; +} + +extern int regs_query_register_offset(const char *name); +extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n); + +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer); + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten + * @offset: offset of the register. + * + * regs_get_register returns the value of a register whose offset from @regs. + * The @offset is the offset of the register in struct pt_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_get_kernel_argument() - get Nth function argument in kernel + * @regs: pt_regs of that context + * @n: function argument number (start from 0) + * + * regs_get_argument() returns @n th argument of the function call. + * + * Note you can get the parameter correctly if the function has no + * more than eight arguments. + */ +static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs, + unsigned int n) +{ + static const int nr_reg_arguments = 8; + static const unsigned int argument_offs[] = { + offsetof(struct pt_regs, a0), + offsetof(struct pt_regs, a1), + offsetof(struct pt_regs, a2), + offsetof(struct pt_regs, a3), + offsetof(struct pt_regs, a4), + offsetof(struct pt_regs, a5), + offsetof(struct pt_regs, a6), + offsetof(struct pt_regs, a7), + }; + + if (n < nr_reg_arguments) + return regs_get_register(regs, argument_offs[n]); + return 0; +} + +static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) +{ + return !(regs->status & SR_PIE); +} + +#endif /* __ASSEMBLER__ */ #endif /* _ASM_RISCV_PTRACE_H */ |
