~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/kernel/ftrace.c

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/arm64/kernel/ftrace.c
  3  *
  4  * Copyright (C) 2013 Linaro Limited
  5  * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU General Public License version 2 as
  9  * published by the Free Software Foundation.
 10  */
 11 
 12 #include <linux/ftrace.h>
 13 #include <linux/swab.h>
 14 #include <linux/uaccess.h>
 15 
 16 #include <asm/cacheflush.h>
 17 #include <asm/ftrace.h>
 18 #include <asm/insn.h>
 19 
 20 #ifdef CONFIG_DYNAMIC_FTRACE
 21 /*
 22  * Replace a single instruction, which may be a branch or NOP.
 23  * If @validate == true, a replaced instruction is checked against 'old'.
 24  */
 25 static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
 26                               bool validate)
 27 {
 28         u32 replaced;
 29 
 30         /*
 31          * Note:
 32          * Due to modules and __init, code can disappear and change,
 33          * we need to protect against faulting as well as code changing.
 34          * We do this by aarch64_insn_*() which use the probe_kernel_*().
 35          *
 36          * No lock is held here because all the modifications are run
 37          * through stop_machine().
 38          */
 39         if (validate) {
 40                 if (aarch64_insn_read((void *)pc, &replaced))
 41                         return -EFAULT;
 42 
 43                 if (replaced != old)
 44                         return -EINVAL;
 45         }
 46         if (aarch64_insn_patch_text_nosync((void *)pc, new))
 47                 return -EPERM;
 48 
 49         return 0;
 50 }
 51 
 52 /*
 53  * Replace tracer function in ftrace_caller()
 54  */
 55 int ftrace_update_ftrace_func(ftrace_func_t func)
 56 {
 57         unsigned long pc;
 58         u32 new;
 59 
 60         pc = (unsigned long)&ftrace_call;
 61         new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func, true);
 62 
 63         return ftrace_modify_code(pc, 0, new, false);
 64 }
 65 
 66 /*
 67  * Turn on the call to ftrace_caller() in instrumented function
 68  */
 69 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 70 {
 71         unsigned long pc = rec->ip;
 72         u32 old, new;
 73 
 74         old = aarch64_insn_gen_nop();
 75         new = aarch64_insn_gen_branch_imm(pc, addr, true);
 76 
 77         return ftrace_modify_code(pc, old, new, true);
 78 }
 79 
 80 /*
 81  * Turn off the call to ftrace_caller() in instrumented function
 82  */
 83 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 84                     unsigned long addr)
 85 {
 86         unsigned long pc = rec->ip;
 87         u32 old, new;
 88 
 89         old = aarch64_insn_gen_branch_imm(pc, addr, true);
 90         new = aarch64_insn_gen_nop();
 91 
 92         return ftrace_modify_code(pc, old, new, true);
 93 }
 94 
 95 int __init ftrace_dyn_arch_init(void)
 96 {
 97         return 0;
 98 }
 99 #endif /* CONFIG_DYNAMIC_FTRACE */
100 
101 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
102 /*
103  * function_graph tracer expects ftrace_return_to_handler() to be called
104  * on the way back to parent. For this purpose, this function is called
105  * in _mcount() or ftrace_caller() to replace return address (*parent) on
106  * the call stack to return_to_handler.
107  *
108  * Note that @frame_pointer is used only for sanity check later.
109  */
110 void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
111                            unsigned long frame_pointer)
112 {
113         unsigned long return_hooker = (unsigned long)&return_to_handler;
114         unsigned long old;
115         struct ftrace_graph_ent trace;
116         int err;
117 
118         if (unlikely(atomic_read(&current->tracing_graph_pause)))
119                 return;
120 
121         /*
122          * Note:
123          * No protection against faulting at *parent, which may be seen
124          * on other archs. It's unlikely on AArch64.
125          */
126         old = *parent;
127         *parent = return_hooker;
128 
129         trace.func = self_addr;
130         trace.depth = current->curr_ret_stack + 1;
131 
132         /* Only trace if the calling function expects to */
133         if (!ftrace_graph_entry(&trace)) {
134                 *parent = old;
135                 return;
136         }
137 
138         err = ftrace_push_return_trace(old, self_addr, &trace.depth,
139                                        frame_pointer);
140         if (err == -EBUSY) {
141                 *parent = old;
142                 return;
143         }
144 }
145 
146 #ifdef CONFIG_DYNAMIC_FTRACE
147 /*
148  * Turn on/off the call to ftrace_graph_caller() in ftrace_caller()
149  * depending on @enable.
150  */
151 static int ftrace_modify_graph_caller(bool enable)
152 {
153         unsigned long pc = (unsigned long)&ftrace_graph_call;
154         u32 branch, nop;
155 
156         branch = aarch64_insn_gen_branch_imm(pc,
157                         (unsigned long)ftrace_graph_caller, false);
158         nop = aarch64_insn_gen_nop();
159 
160         if (enable)
161                 return ftrace_modify_code(pc, nop, branch, true);
162         else
163                 return ftrace_modify_code(pc, branch, nop, true);
164 }
165 
166 int ftrace_enable_ftrace_graph_caller(void)
167 {
168         return ftrace_modify_graph_caller(true);
169 }
170 
171 int ftrace_disable_ftrace_graph_caller(void)
172 {
173         return ftrace_modify_graph_caller(false);
174 }
175 #endif /* CONFIG_DYNAMIC_FTRACE */
176 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
177 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp