1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * Copyright (C) 2022 Loongson Technology Corporation Limited |
4 | */ |
5 | |
6 | #include <linux/init.h> |
7 | #include <linux/ftrace.h> |
8 | #include <linux/syscalls.h> |
9 | #include <linux/uaccess.h> |
10 | |
11 | #include <asm/asm.h> |
12 | #include <asm/asm-offsets.h> |
13 | #include <asm/cacheflush.h> |
14 | #include <asm/inst.h> |
15 | #include <asm/loongarch.h> |
16 | #include <asm/syscall.h> |
17 | |
18 | #include <asm-generic/sections.h> |
19 | |
20 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
21 | |
22 | /* |
23 | * As `call _mcount` follows LoongArch psABI, ra-saved operation and |
24 | * stack operation can be found before this insn. |
25 | */ |
26 | |
27 | static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off) |
28 | { |
29 | int limit = 32; |
30 | union loongarch_instruction *insn; |
31 | |
32 | insn = (union loongarch_instruction *)insn_addr; |
33 | |
34 | do { |
35 | insn--; |
36 | limit--; |
37 | |
38 | if (is_ra_save_ins(insn)) |
39 | *ra_off = -((1 << 12) - insn->reg2i12_format.immediate); |
40 | |
41 | } while (!is_stack_alloc_ins(insn) && limit); |
42 | |
43 | if (!limit) |
44 | return -EINVAL; |
45 | |
46 | return 0; |
47 | } |
48 | |
49 | void prepare_ftrace_return(unsigned long self_addr, |
50 | unsigned long callsite_sp, unsigned long old) |
51 | { |
52 | int ra_off; |
53 | unsigned long return_hooker = (unsigned long)&return_to_handler; |
54 | |
55 | if (unlikely(ftrace_graph_is_dead())) |
56 | return; |
57 | |
58 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) |
59 | return; |
60 | |
61 | if (ftrace_get_parent_ra_addr(insn_addr: self_addr, ra_off: &ra_off)) |
62 | goto out; |
63 | |
64 | if (!function_graph_enter(ret: old, func: self_addr, frame_pointer: 0, NULL)) |
65 | *(unsigned long *)(callsite_sp + ra_off) = return_hooker; |
66 | |
67 | return; |
68 | |
69 | out: |
70 | ftrace_graph_stop(); |
71 | WARN_ON(1); |
72 | } |
73 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
74 |