xref: /linux/arch/riscv/include/asm/ptrace.h (revision 119b1e61a769aa98e68599f44721661a4d8c55f3)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2012 Regents of the University of California
4  */
5 
6 #ifndef _ASM_RISCV_PTRACE_H
7 #define _ASM_RISCV_PTRACE_H
8 
9 #include <uapi/asm/ptrace.h>
10 #include <asm/csr.h>
11 #include <linux/compiler.h>
12 
13 #ifndef __ASSEMBLY__
14 
15 struct pt_regs {
16 	unsigned long epc;
17 	unsigned long ra;
18 	unsigned long sp;
19 	unsigned long gp;
20 	unsigned long tp;
21 	unsigned long t0;
22 	unsigned long t1;
23 	unsigned long t2;
24 	unsigned long s0;
25 	unsigned long s1;
26 	struct_group(a_regs,
27 		unsigned long a0;
28 		unsigned long a1;
29 		unsigned long a2;
30 		unsigned long a3;
31 		unsigned long a4;
32 		unsigned long a5;
33 		unsigned long a6;
34 		unsigned long a7;
35 	);
36 	unsigned long s2;
37 	unsigned long s3;
38 	unsigned long s4;
39 	unsigned long s5;
40 	unsigned long s6;
41 	unsigned long s7;
42 	unsigned long s8;
43 	unsigned long s9;
44 	unsigned long s10;
45 	unsigned long s11;
46 	unsigned long t3;
47 	unsigned long t4;
48 	unsigned long t5;
49 	unsigned long t6;
50 	/* Supervisor/Machine CSRs */
51 	unsigned long status;
52 	unsigned long badaddr;
53 	unsigned long cause;
54 	/* a0 value before the syscall */
55 	unsigned long orig_a0;
56 };
57 
58 #define PTRACE_SYSEMU			0x1f
59 #define PTRACE_SYSEMU_SINGLESTEP	0x20
60 
61 #ifdef CONFIG_64BIT
62 #define REG_FMT "%016lx"
63 #else
64 #define REG_FMT "%08lx"
65 #endif
66 
67 #define user_mode(regs) (((regs)->status & SR_PP) == 0)
68 
69 #define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0)
70 
71 /* Helpers for working with the instruction pointer */
instruction_pointer(struct pt_regs * regs)72 static inline unsigned long instruction_pointer(struct pt_regs *regs)
73 {
74 	return regs->epc;
75 }
instruction_pointer_set(struct pt_regs * regs,unsigned long val)76 static inline void instruction_pointer_set(struct pt_regs *regs,
77 					   unsigned long val)
78 {
79 	regs->epc = val;
80 }
81 
82 #define profile_pc(regs) instruction_pointer(regs)
83 
84 /* Helpers for working with the user stack pointer */
user_stack_pointer(struct pt_regs * regs)85 static inline unsigned long user_stack_pointer(struct pt_regs *regs)
86 {
87 	return regs->sp;
88 }
user_stack_pointer_set(struct pt_regs * regs,unsigned long val)89 static inline void user_stack_pointer_set(struct pt_regs *regs,
90 					  unsigned long val)
91 {
92 	regs->sp =  val;
93 }
94 
95 /* Valid only for Kernel mode traps. */
kernel_stack_pointer(struct pt_regs * regs)96 static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
97 {
98 	return regs->sp;
99 }
100 
101 /* Helpers for working with the frame pointer */
frame_pointer(struct pt_regs * regs)102 static inline unsigned long frame_pointer(struct pt_regs *regs)
103 {
104 	return regs->s0;
105 }
frame_pointer_set(struct pt_regs * regs,unsigned long val)106 static inline void frame_pointer_set(struct pt_regs *regs,
107 				     unsigned long val)
108 {
109 	regs->s0 = val;
110 }
111 
regs_return_value(struct pt_regs * regs)112 static inline unsigned long regs_return_value(struct pt_regs *regs)
113 {
114 	return regs->a0;
115 }
116 
regs_set_return_value(struct pt_regs * regs,unsigned long val)117 static inline void regs_set_return_value(struct pt_regs *regs,
118 					 unsigned long val)
119 {
120 	regs->a0 = val;
121 }
122 
123 extern int regs_query_register_offset(const char *name);
124 extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
125 					       unsigned int n);
126 
127 void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
128 			   unsigned long frame_pointer);
129 
130 /**
131  * regs_get_register() - get register value from its offset
132  * @regs:	pt_regs from which register value is gotten
133  * @offset:	offset of the register.
134  *
135  * regs_get_register returns the value of a register whose offset from @regs.
136  * The @offset is the offset of the register in struct pt_regs.
137  * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
138  */
regs_get_register(struct pt_regs * regs,unsigned int offset)139 static inline unsigned long regs_get_register(struct pt_regs *regs,
140 					      unsigned int offset)
141 {
142 	if (unlikely(offset > MAX_REG_OFFSET))
143 		return 0;
144 
145 	return *(unsigned long *)((unsigned long)regs + offset);
146 }
147 
148 /**
149  * regs_get_kernel_argument() - get Nth function argument in kernel
150  * @regs:       pt_regs of that context
151  * @n:          function argument number (start from 0)
152  *
153  * regs_get_argument() returns @n th argument of the function call.
154  *
155  * Note you can get the parameter correctly if the function has no
156  * more than eight arguments.
157  */
regs_get_kernel_argument(struct pt_regs * regs,unsigned int n)158 static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
159 						unsigned int n)
160 {
161 	static const int nr_reg_arguments = 8;
162 	static const unsigned int argument_offs[] = {
163 		offsetof(struct pt_regs, a0),
164 		offsetof(struct pt_regs, a1),
165 		offsetof(struct pt_regs, a2),
166 		offsetof(struct pt_regs, a3),
167 		offsetof(struct pt_regs, a4),
168 		offsetof(struct pt_regs, a5),
169 		offsetof(struct pt_regs, a6),
170 		offsetof(struct pt_regs, a7),
171 	};
172 
173 	if (n < nr_reg_arguments)
174 		return regs_get_register(regs, argument_offs[n]);
175 	return 0;
176 }
177 
regs_irqs_disabled(struct pt_regs * regs)178 static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
179 {
180 	return !(regs->status & SR_PIE);
181 }
182 
183 #endif /* __ASSEMBLY__ */
184 
185 #endif /* _ASM_RISCV_PTRACE_H */
186