Linux v6.18.37 · ARM64

arch/arm64/kernel/ftrace.c

전체 목록

Linux v6.18.37 · 원본 파일 · 온라인 원본

1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * arch/arm64/kernel/ftrace.c
4 *
5 * Copyright (C) 2013 Linaro Limited
6 * Author: AKASHI Takahiro <[email protected]>
7 */
8
9#include <linux/ftrace.h>
10#include <linux/module.h>
11#include <linux/swab.h>
12#include <linux/uaccess.h>
13
14#include <asm/cacheflush.h>
15#include <asm/debug-monitors.h>
16#include <asm/ftrace.h>
17#include <asm/insn.h>
18#include <asm/text-patching.h>
19
20#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
21struct fregs_offset {
22	const char *name;
23	int offset;
24};
25
26#define FREGS_OFFSET(n, field)					\
27{								\
28	.name = n,						\
29	.offset = offsetof(struct __arch_ftrace_regs, field),	\
30}
31
32static const struct fregs_offset fregs_offsets[] = {
33	FREGS_OFFSET("x0", regs[0]),
34	FREGS_OFFSET("x1", regs[1]),
35	FREGS_OFFSET("x2", regs[2]),
36	FREGS_OFFSET("x3", regs[3]),
37	FREGS_OFFSET("x4", regs[4]),
38	FREGS_OFFSET("x5", regs[5]),
39	FREGS_OFFSET("x6", regs[6]),
40	FREGS_OFFSET("x7", regs[7]),
41	FREGS_OFFSET("x8", regs[8]),
42
43	FREGS_OFFSET("x29", fp),
44	FREGS_OFFSET("x30", lr),
45	FREGS_OFFSET("lr", lr),
46
47	FREGS_OFFSET("sp", sp),
48	FREGS_OFFSET("pc", pc),
49};
50
51int ftrace_regs_query_register_offset(const char *name)
52{
53	for (int i = 0; i < ARRAY_SIZE(fregs_offsets); i++) {
54		const struct fregs_offset *roff = &fregs_offsets[i];
55		if (!strcmp(roff->name, name))
56			return roff->offset;
57	}
58
59	return -EINVAL;
60}
61#endif
62
63unsigned long ftrace_call_adjust(unsigned long addr)
64{
65	/*
66	 * When using mcount, addr is the address of the mcount call
67	 * instruction, and no adjustment is necessary.
68	 */
69	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
70		return addr;
71
72	/*
73	 * When using patchable-function-entry without pre-function NOPS, addr
74	 * is the address of the first NOP after the function entry point.
75	 *
76	 * The compiler has either generated:
77	 *
78	 * addr+00:	func:	NOP		// To be patched to MOV X9, LR
79	 * addr+04:		NOP		// To be patched to BL <caller>
80	 *
81	 * Or:
82	 *
83	 * addr-04:		BTI	C
84	 * addr+00:	func:	NOP		// To be patched to MOV X9, LR
85	 * addr+04:		NOP		// To be patched to BL <caller>
86	 *
87	 * We must adjust addr to the address of the NOP which will be patched
88	 * to `BL <caller>`, which is at `addr + 4` bytes in either case.
89	 *
90	 */
91	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
92		return addr + AARCH64_INSN_SIZE;
93
94	/*
95	 * When using patchable-function-entry with pre-function NOPs, addr is
96	 * the address of the first pre-function NOP.
97	 *
98	 * Starting from an 8-byte aligned base, the compiler has either
99	 * generated:
100	 *
101	 * addr+00:		NOP		// Literal (first 32 bits)
102	 * addr+04:		NOP		// Literal (last 32 bits)
103	 * addr+08:	func:	NOP		// To be patched to MOV X9, LR
104	 * addr+12:		NOP		// To be patched to BL <caller>
105	 *
106	 * Or:
107	 *
108	 * addr+00:		NOP		// Literal (first 32 bits)
109	 * addr+04:		NOP		// Literal (last 32 bits)
110	 * addr+08:	func:	BTI	C
111	 * addr+12:		NOP		// To be patched to MOV X9, LR
112	 * addr+16:		NOP		// To be patched to BL <caller>
113	 *
114	 * We must adjust addr to the address of the NOP which will be patched
115	 * to `BL <caller>`, which is at either addr+12 or addr+16 depending on
116	 * whether there is a BTI.
117	 */
118
119	if (!IS_ALIGNED(addr, sizeof(unsigned long))) {
120		WARN_RATELIMIT(1, "Misaligned patch-site %pS\n",
121			       (void *)(addr + 8));
122		return 0;
123	}
124
125	/* Skip the NOPs placed before the function entry point */
126	addr += 2 * AARCH64_INSN_SIZE;
127
128	/* Skip any BTI */
129	if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
130		u32 insn = le32_to_cpu(*(__le32 *)addr);
131
132		if (aarch64_insn_is_bti(insn)) {
133			addr += AARCH64_INSN_SIZE;
134		} else if (insn != aarch64_insn_gen_nop()) {
135			WARN_RATELIMIT(1, "unexpected insn in patch-site %pS: 0x%08x\n",
136				       (void *)addr, insn);
137		}
138	}
139
140	/* Skip the first NOP after function entry */
141	addr += AARCH64_INSN_SIZE;
142
143	return addr;
144}
145
146/* Convert fentry_ip to the symbol address without kallsyms */
147unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip)
148{
149	u32 insn;
150
151	/*
152	 * When using patchable-function-entry without pre-function NOPS, ftrace
153	 * entry is the address of the first NOP after the function entry point.
154	 *
155	 * The compiler has either generated:
156	 *
157	 * func+00:	func:	NOP		// To be patched to MOV X9, LR
158	 * func+04:		NOP		// To be patched to BL <caller>
159	 *
160	 * Or:
161	 *
162	 * func-04:		BTI	C
163	 * func+00:	func:	NOP		// To be patched to MOV X9, LR
164	 * func+04:		NOP		// To be patched to BL <caller>
165	 *
166	 * The fentry_ip is the address of `BL <caller>` which is at `func + 4`
167	 * bytes in either case.
168	 */
169	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
170		return fentry_ip - AARCH64_INSN_SIZE;
171
172	/*
173	 * When using patchable-function-entry with pre-function NOPs, BTI is
174	 * a bit different.
175	 *
176	 * func+00:	func:	NOP		// To be patched to MOV X9, LR
177	 * func+04:		NOP		// To be patched to BL <caller>
178	 *
179	 * Or:
180	 *
181	 * func+00:	func:	BTI	C
182	 * func+04:		NOP		// To be patched to MOV X9, LR
183	 * func+08:		NOP		// To be patched to BL <caller>
184	 *
185	 * The fentry_ip is the address of `BL <caller>` which is at either
186	 * `func + 4` or `func + 8` depends on whether there is a BTI.
187	 */
188
189	/* If there is no BTI, the func address should be one instruction before. */
190	if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
191		return fentry_ip - AARCH64_INSN_SIZE;
192
193	/* We want to be extra safe in case entry ip is on the page edge,
194	 * but otherwise we need to avoid get_kernel_nofault()'s overhead.
195	 */
196	if ((fentry_ip & ~PAGE_MASK) < AARCH64_INSN_SIZE * 2) {
197		if (get_kernel_nofault(insn, (u32 *)(fentry_ip - AARCH64_INSN_SIZE * 2)))
198			return 0;
199	} else {
200		insn = *(u32 *)(fentry_ip - AARCH64_INSN_SIZE * 2);
201	}
202
203	if (aarch64_insn_is_bti(le32_to_cpu((__le32)insn)))
204		return fentry_ip - AARCH64_INSN_SIZE * 2;
205
206	return fentry_ip - AARCH64_INSN_SIZE;
207}
208
209/*
210 * Replace a single instruction, which may be a branch or NOP.
211 * If @validate == true, a replaced instruction is checked against 'old'.
212 */
213static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
214			      bool validate)
215{
216	u32 replaced;
217
218	/*
219	 * Note:
220	 * We are paranoid about modifying text, as if a bug were to happen, it
221	 * could cause us to read or write to someplace that could cause harm.
222	 * Carefully read and modify the code with aarch64_insn_*() which uses
223	 * probe_kernel_*(), and make sure what we read is what we expected it
224	 * to be before modifying it.
225	 */
226	if (validate) {
227		if (aarch64_insn_read((void *)pc, &replaced))
228			return -EFAULT;
229
230		if (replaced != old)
231			return -EINVAL;
232	}
233	if (aarch64_insn_patch_text_nosync((void *)pc, new))
234		return -EPERM;
235
236	return 0;
237}
238
239/*
240 * Replace tracer function in ftrace_caller()
241 */
242int ftrace_update_ftrace_func(ftrace_func_t func)
243{
244	unsigned long pc;
245	u32 new;
246
247	/*
248	 * When using CALL_OPS, the function to call is associated with the
249	 * call site, and we don't have a global function pointer to update.
250	 */
251	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
252		return 0;
253
254	pc = (unsigned long)ftrace_call;
255	new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func,
256					  AARCH64_INSN_BRANCH_LINK);
257
258	return ftrace_modify_code(pc, 0, new, false);
259}
260
261static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
262{
263#ifdef CONFIG_MODULES
264	struct plt_entry *plt = NULL;
265
266	if (within_module_mem_type(addr, mod, MOD_INIT_TEXT))
267		plt = mod->arch.init_ftrace_trampolines;
268	else if (within_module_mem_type(addr, mod, MOD_TEXT))
269		plt = mod->arch.ftrace_trampolines;
270	else
271		return NULL;
272
273	return &plt[FTRACE_PLT_IDX];
274#else
275	return NULL;
276#endif
277}
278
279static bool reachable_by_bl(unsigned long addr, unsigned long pc)
280{
281	long offset = (long)addr - (long)pc;
282
283	return offset >= -SZ_128M && offset < SZ_128M;
284}
285
286/*
287 * Find the address the callsite must branch to in order to reach '*addr'.
288 *
289 * Due to the limited range of 'BL' instructions, modules may be placed too far
290 * away to branch directly and must use a PLT.
291 *
292 * Returns true when '*addr' contains a reachable target address, or has been
293 * modified to contain a PLT address. Returns false otherwise.
294 */
295static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
296				      struct module *mod,
297				      unsigned long *addr)
298{
299	unsigned long pc = rec->ip;
300	struct plt_entry *plt;
301
302	/*
303	 * If a custom trampoline is unreachable, rely on the ftrace_caller
304	 * trampoline which knows how to indirectly reach that trampoline
305	 * through ops->direct_call.
306	 */
307	if (*addr != FTRACE_ADDR && !reachable_by_bl(*addr, pc))
308		*addr = FTRACE_ADDR;
309
310	/*
311	 * When the target is within range of the 'BL' instruction, use 'addr'
312	 * as-is and branch to that directly.
313	 */
314	if (reachable_by_bl(*addr, pc))
315		return true;
316
317	/*
318	 * When the target is outside of the range of a 'BL' instruction, we
319	 * must use a PLT to reach it. We can only place PLTs for modules, and
320	 * only when module PLT support is built-in.
321	 */
322	if (!IS_ENABLED(CONFIG_MODULES))
323		return false;
324
325	/*
326	 * 'mod' is only set at module load time, but if we end up
327	 * dealing with an out-of-range condition, we can assume it
328	 * is due to a module being loaded far away from the kernel.
329	 *
330	 * NOTE: __module_text_address() must be called within a RCU read
331	 * section, but we can rely on ftrace_lock to ensure that 'mod'
332	 * retains its validity throughout the remainder of this code.
333	 */
334	if (!mod) {
335		guard(rcu)();
336		mod = __module_text_address(pc);
337	}
338
339	if (WARN_ON(!mod))
340		return false;
341
342	plt = get_ftrace_plt(mod, pc);
343	if (!plt) {
344		pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
345		return false;
346	}
347
348	*addr = (unsigned long)plt;
349	return true;
350}
351
352#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
353static const struct ftrace_ops *arm64_rec_get_ops(struct dyn_ftrace *rec)
354{
355	const struct ftrace_ops *ops = NULL;
356
357	if (rec->flags & FTRACE_FL_CALL_OPS_EN) {
358		ops = ftrace_find_unique_ops(rec);
359		WARN_ON_ONCE(!ops);
360	}
361
362	if (!ops)
363		ops = &ftrace_list_ops;
364
365	return ops;
366}
367
368static int ftrace_rec_set_ops(const struct dyn_ftrace *rec,
369			      const struct ftrace_ops *ops)
370{
371	unsigned long literal = ALIGN_DOWN(rec->ip - 12, 8);
372	return aarch64_insn_write_literal_u64((void *)literal,
373					      (unsigned long)ops);
374}
375
376static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec)
377{
378	return ftrace_rec_set_ops(rec, &ftrace_nop_ops);
379}
380
381static int ftrace_rec_update_ops(struct dyn_ftrace *rec)
382{
383	return ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
384}
385#else
386static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; }
387static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; }
388#endif
389
390/*
391 * Turn on the call to ftrace_caller() in instrumented function
392 */
393int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
394{
395	unsigned long pc = rec->ip;
396	u32 old, new;
397	int ret;
398
399	ret = ftrace_rec_update_ops(rec);
400	if (ret)
401		return ret;
402
403	if (!ftrace_find_callable_addr(rec, NULL, &addr))
404		return -EINVAL;
405
406	old = aarch64_insn_gen_nop();
407	new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
408
409	return ftrace_modify_code(pc, old, new, true);
410}
411
412#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
413int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
414		       unsigned long addr)
415{
416	unsigned long pc = rec->ip;
417	u32 old, new;
418	int ret;
419
420	ret = ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
421	if (ret)
422		return ret;
423
424	if (!ftrace_find_callable_addr(rec, NULL, &old_addr))
425		return -EINVAL;
426	if (!ftrace_find_callable_addr(rec, NULL, &addr))
427		return -EINVAL;
428
429	old = aarch64_insn_gen_branch_imm(pc, old_addr,
430					  AARCH64_INSN_BRANCH_LINK);
431	new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
432
433	return ftrace_modify_code(pc, old, new, true);
434}
435#endif
436
437#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
438/*
439 * The compiler has inserted two NOPs before the regular function prologue.
440 * All instrumented functions follow the AAPCS, so x0-x8 and x19-x30 are live,
441 * and x9-x18 are free for our use.
442 *
443 * At runtime we want to be able to swing a single NOP <-> BL to enable or
444 * disable the ftrace call. The BL requires us to save the original LR value,
445 * so here we insert a <MOV X9, LR> over the first NOP so the instructions
446 * before the regular prologue are:
447 *
448 * | Compiled | Disabled   | Enabled    |
449 * +----------+------------+------------+
450 * | NOP      | MOV X9, LR | MOV X9, LR |
451 * | NOP      | NOP        | BL <entry> |
452 *
453 * The LR value will be recovered by ftrace_caller, and restored into LR
454 * before returning to the regular function prologue. When a function is not
455 * being traced, the MOV is not harmful given x9 is not live per the AAPCS.
456 *
457 * Note: ftrace_process_locs() has pre-adjusted rec->ip to be the address of
458 * the BL.
459 */
460int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
461{
462	unsigned long pc = rec->ip - AARCH64_INSN_SIZE;
463	u32 old, new;
464	int ret;
465
466	ret = ftrace_rec_set_nop_ops(rec);
467	if (ret)
468		return ret;
469
470	old = aarch64_insn_gen_nop();
471	new = aarch64_insn_gen_move_reg(AARCH64_INSN_REG_9,
472					AARCH64_INSN_REG_LR,
473					AARCH64_INSN_VARIANT_64BIT);
474	return ftrace_modify_code(pc, old, new, true);
475}
476#endif
477
478/*
479 * Turn off the call to ftrace_caller() in instrumented function
480 */
481int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
482		    unsigned long addr)
483{
484	unsigned long pc = rec->ip;
485	u32 old = 0, new;
486	int ret;
487
488	new = aarch64_insn_gen_nop();
489
490	ret = ftrace_rec_set_nop_ops(rec);
491	if (ret)
492		return ret;
493
494	/*
495	 * When using mcount, callsites in modules may have been initalized to
496	 * call an arbitrary module PLT (which redirects to the _mcount stub)
497	 * rather than the ftrace PLT we'll use at runtime (which redirects to
498	 * the ftrace trampoline). We can ignore the old PLT when initializing
499	 * the callsite.
500	 *
501	 * Note: 'mod' is only set at module load time.
502	 */
503	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) && mod)
504		return aarch64_insn_patch_text_nosync((void *)pc, new);
505
506	if (!ftrace_find_callable_addr(rec, mod, &addr))
507		return -EINVAL;
508
509	old = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
510
511	return ftrace_modify_code(pc, old, new, true);
512}
513
514void arch_ftrace_update_code(int command)
515{
516	command |= FTRACE_MAY_SLEEP;
517	ftrace_modify_all_code(command);
518}
519
520#ifdef CONFIG_FUNCTION_GRAPH_TRACER
521/*
522 * function_graph tracer expects ftrace_return_to_handler() to be called
523 * on the way back to parent. For this purpose, this function is called
524 * in _mcount() or ftrace_caller() to replace return address (*parent) on
525 * the call stack to return_to_handler.
526 */
527void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
528			   unsigned long frame_pointer)
529{
530	unsigned long return_hooker = (unsigned long)&return_to_handler;
531	unsigned long old;
532
533	if (unlikely(atomic_read(&current->tracing_graph_pause)))
534		return;
535
536	/*
537	 * Note:
538	 * No protection against faulting at *parent, which may be seen
539	 * on other archs. It's unlikely on AArch64.
540	 */
541	old = *parent;
542
543	if (!function_graph_enter(old, self_addr, frame_pointer,
544	    (void *)frame_pointer)) {
545		*parent = return_hooker;
546	}
547}
548
549#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
550void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
551		       struct ftrace_ops *op, struct ftrace_regs *fregs)
552{
553	unsigned long return_hooker = (unsigned long)&return_to_handler;
554	unsigned long frame_pointer = arch_ftrace_regs(fregs)->fp;
555	unsigned long *parent = &arch_ftrace_regs(fregs)->lr;
556	unsigned long old;
557
558	if (unlikely(atomic_read(&current->tracing_graph_pause)))
559		return;
560
561	old = *parent;
562
563	if (!function_graph_enter_regs(old, ip, frame_pointer,
564				       (void *)frame_pointer, fregs)) {
565		*parent = return_hooker;
566	}
567}
568#else
569/*
570 * Turn on/off the call to ftrace_graph_caller() in ftrace_caller()
571 * depending on @enable.
572 */
573static int ftrace_modify_graph_caller(bool enable)
574{
575	unsigned long pc = (unsigned long)&ftrace_graph_call;
576	u32 branch, nop;
577
578	branch = aarch64_insn_gen_branch_imm(pc,
579					     (unsigned long)ftrace_graph_caller,
580					     AARCH64_INSN_BRANCH_NOLINK);
581	nop = aarch64_insn_gen_nop();
582
583	if (enable)
584		return ftrace_modify_code(pc, nop, branch, true);
585	else
586		return ftrace_modify_code(pc, branch, nop, true);
587}
588
589int ftrace_enable_ftrace_graph_caller(void)
590{
591	return ftrace_modify_graph_caller(true);
592}
593
594int ftrace_disable_ftrace_graph_caller(void)
595{
596	return ftrace_modify_graph_caller(false);
597}
598#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
599#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
맨 위로 ↑