Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/riscv/include/asm/ftrace.h
26471 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/* Copyright (C) 2017 Andes Technology Corporation */
3
4
#ifndef _ASM_RISCV_FTRACE_H
5
#define _ASM_RISCV_FTRACE_H
6
7
/*
8
* The graph frame test is not possible if CONFIG_FRAME_POINTER is not enabled.
9
* Check arch/riscv/kernel/mcount.S for detail.
10
*/
11
#if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER)
12
#define HAVE_FUNCTION_GRAPH_FP_TEST
13
#endif
14
15
#define ARCH_SUPPORTS_FTRACE_OPS 1
16
#ifndef __ASSEMBLY__
17
18
extern void *return_address(unsigned int level);
19
20
#define ftrace_return_address(n) return_address(n)
21
22
void _mcount(void);
23
unsigned long ftrace_call_adjust(unsigned long addr);
24
unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip);
25
#define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip)
26
27
/*
28
* Let's do like x86/arm64 and ignore the compat syscalls.
29
*/
30
#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
31
static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
32
{
33
return is_compat_task();
34
}
35
36
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
37
static inline bool arch_syscall_match_sym_name(const char *sym,
38
const char *name)
39
{
40
/*
41
* Since all syscall functions have __riscv_ prefix, we must skip it.
42
* However, as we described above, we decided to ignore compat
43
* syscalls, so we don't care about __riscv_compat_ prefix here.
44
*/
45
return !strcmp(sym + 8, name);
46
}
47
48
struct dyn_arch_ftrace {
49
};
50
#endif
51
52
#ifdef CONFIG_DYNAMIC_FTRACE
53
/*
54
* A general call in RISC-V is a pair of insts:
55
* 1) auipc: setting high-20 pc-related bits to ra register
56
* 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to
57
* return address (original pc + 4)
58
*
59
* The first 2 instructions for each tracable function is compiled to 2 nop
60
* instructions. Then, the kernel initializes the first instruction to auipc at
61
* boot time (<ftrace disable>). The second instruction is patched to jalr to
62
* start the trace.
63
*
64
*<Image>:
65
* 0: nop
66
* 4: nop
67
*
68
*<ftrace enable>:
69
* 0: auipc t0, 0x?
70
* 4: jalr t0, ?(t0)
71
*
72
*<ftrace disable>:
73
* 0: auipc t0, 0x?
74
* 4: nop
75
*
76
* Dynamic ftrace generates probes to call sites, so we must deal with
77
* both auipc and jalr at the same time.
78
*/
79
80
#define MCOUNT_ADDR ((unsigned long)_mcount)
81
#define JALR_SIGN_MASK (0x00000800)
82
#define JALR_OFFSET_MASK (0x00000fff)
83
#define AUIPC_OFFSET_MASK (0xfffff000)
84
#define AUIPC_PAD (0x00001000)
85
#define JALR_SHIFT 20
86
#define JALR_T0 (0x000282e7)
87
#define AUIPC_T0 (0x00000297)
88
#define JALR_RANGE (JALR_SIGN_MASK - 1)
89
90
#define to_jalr_t0(offset) \
91
(((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_T0)
92
93
#define to_auipc_t0(offset) \
94
((offset & JALR_SIGN_MASK) ? \
95
(((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_T0) : \
96
((offset & AUIPC_OFFSET_MASK) | AUIPC_T0))
97
98
#define make_call_t0(caller, callee, call) \
99
do { \
100
unsigned int offset = \
101
(unsigned long) (callee) - (unsigned long) (caller); \
102
call[0] = to_auipc_t0(offset); \
103
call[1] = to_jalr_t0(offset); \
104
} while (0)
105
106
/*
107
* Only the jalr insn in the auipc+jalr is patched, so we make it 4
108
* bytes here.
109
*/
110
#define MCOUNT_INSN_SIZE 4
111
#define MCOUNT_AUIPC_SIZE 4
112
#define MCOUNT_JALR_SIZE 4
113
#define MCOUNT_NOP4_SIZE 4
114
115
#ifndef __ASSEMBLY__
116
struct dyn_ftrace;
117
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
118
#define ftrace_init_nop ftrace_init_nop
119
120
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
121
#define arch_ftrace_get_regs(regs) NULL
122
#define HAVE_ARCH_FTRACE_REGS
123
struct ftrace_ops;
124
struct ftrace_regs;
125
#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs))
126
127
struct __arch_ftrace_regs {
128
unsigned long epc;
129
unsigned long ra;
130
unsigned long sp;
131
unsigned long s0;
132
unsigned long t1;
133
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
134
unsigned long direct_tramp;
135
#endif
136
union {
137
unsigned long args[8];
138
struct {
139
unsigned long a0;
140
unsigned long a1;
141
unsigned long a2;
142
unsigned long a3;
143
unsigned long a4;
144
unsigned long a5;
145
unsigned long a6;
146
unsigned long a7;
147
#ifdef CONFIG_CC_IS_CLANG
148
unsigned long t2;
149
unsigned long t3;
150
unsigned long t4;
151
unsigned long t5;
152
unsigned long t6;
153
#endif
154
};
155
};
156
};
157
158
static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs
159
*fregs)
160
{
161
return arch_ftrace_regs(fregs)->epc;
162
}
163
164
static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
165
unsigned long pc)
166
{
167
arch_ftrace_regs(fregs)->epc = pc;
168
}
169
170
static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
171
{
172
return arch_ftrace_regs(fregs)->sp;
173
}
174
175
static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
176
{
177
return arch_ftrace_regs(fregs)->s0;
178
}
179
180
static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs,
181
unsigned int n)
182
{
183
if (n < 8)
184
return arch_ftrace_regs(fregs)->args[n];
185
return 0;
186
}
187
188
static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
189
{
190
return arch_ftrace_regs(fregs)->a0;
191
}
192
193
static __always_inline unsigned long ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
194
{
195
return arch_ftrace_regs(fregs)->ra;
196
}
197
198
static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs,
199
unsigned long ret)
200
{
201
arch_ftrace_regs(fregs)->a0 = ret;
202
}
203
204
static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs)
205
{
206
arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra;
207
}
208
209
static __always_inline struct pt_regs *
210
ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
211
{
212
struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
213
214
memcpy(&regs->a_regs, afregs->args, sizeof(afregs->args));
215
regs->epc = afregs->epc;
216
regs->ra = afregs->ra;
217
regs->sp = afregs->sp;
218
regs->s0 = afregs->s0;
219
regs->t1 = afregs->t1;
220
return regs;
221
}
222
223
int ftrace_regs_query_register_offset(const char *name);
224
225
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
226
struct ftrace_ops *op, struct ftrace_regs *fregs);
227
#define ftrace_graph_func ftrace_graph_func
228
229
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
230
static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
231
{
232
arch_ftrace_regs(fregs)->t1 = addr;
233
}
234
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
235
236
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
237
238
#endif /* __ASSEMBLY__ */
239
240
#endif /* CONFIG_DYNAMIC_FTRACE */
241
242
#endif /* _ASM_RISCV_FTRACE_H */
243
244