Commit | Line | Data |
---|---|---|
aba09b44 MH |
1 | .. SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | ================================== | |
4 | Fprobe - Function entry/exit probe | |
5 | ================================== | |
6 | ||
7 | .. Author: Masami Hiramatsu <mhiramat@kernel.org> | |
8 | ||
9 | Introduction | |
10 | ============ | |
11 | ||
12 | Fprobe is a function entry/exit probe mechanism based on ftrace. | |
13 | Instead of using ftrace full feature, if you only want to attach callbacks | |
14 | on function entry and exit, similar to the kprobes and kretprobes, you can | |
15 | use fprobe. Compared with kprobes and kretprobes, fprobe gives faster | |
16 | instrumentation for multiple functions with single handler. This document | |
17 | describes how to use fprobe. | |
18 | ||
19 | The usage of fprobe | |
20 | =================== | |
21 | ||
22 | The fprobe is a wrapper of ftrace (+ kretprobe-like return callback) to | |
23 | attach callbacks to multiple function entry and exit. User needs to set up | |
24 | the `struct fprobe` and pass it to `register_fprobe()`. | |
25 | ||
26 | Typically, `fprobe` data structure is initialized with the `entry_handler` | |
27 | and/or `exit_handler` as below. | |
28 | ||
29 | .. code-block:: c | |
30 | ||
31 | struct fprobe fp = { | |
32 | .entry_handler = my_entry_callback, | |
33 | .exit_handler = my_exit_callback, | |
34 | }; | |
35 | ||
36 | To enable the fprobe, call one of register_fprobe(), register_fprobe_ips(), and | |
37 | register_fprobe_syms(). These functions register the fprobe with different types | |
38 | of parameters. | |
39 | ||
40 | The register_fprobe() enables a fprobe by function-name filters. | |
41 | E.g. this enables @fp on "func*()" function except "func2()".:: | |
42 | ||
43 | register_fprobe(&fp, "func*", "func2"); | |
44 | ||
45 | The register_fprobe_ips() enables a fprobe by ftrace-location addresses. | |
46 | E.g. | |
47 | ||
48 | .. code-block:: c | |
49 | ||
50 | unsigned long ips[] = { 0x.... }; | |
51 | ||
52 | register_fprobe_ips(&fp, ips, ARRAY_SIZE(ips)); | |
53 | ||
54 | And the register_fprobe_syms() enables a fprobe by symbol names. | |
55 | E.g. | |
56 | ||
57 | .. code-block:: c | |
58 | ||
59 | char syms[] = {"func1", "func2", "func3"}; | |
60 | ||
61 | register_fprobe_syms(&fp, syms, ARRAY_SIZE(syms)); | |
62 | ||
63 | To disable (remove from functions) this fprobe, call:: | |
64 | ||
65 | unregister_fprobe(&fp); | |
66 | ||
67 | You can temporally (soft) disable the fprobe by:: | |
68 | ||
69 | disable_fprobe(&fp); | |
70 | ||
71 | and resume by:: | |
72 | ||
73 | enable_fprobe(&fp); | |
74 | ||
75 | The above is defined by including the header:: | |
76 | ||
77 | #include <linux/fprobe.h> | |
78 | ||
79 | Same as ftrace, the registered callbacks will start being called some time | |
80 | after the register_fprobe() is called and before it returns. See | |
81 | :file:`Documentation/trace/ftrace.rst`. | |
82 | ||
83 | Also, the unregister_fprobe() will guarantee that the both enter and exit | |
84 | handlers are no longer being called by functions after unregister_fprobe() | |
85 | returns as same as unregister_ftrace_function(). | |
86 | ||
87 | The fprobe entry/exit handler | |
88 | ============================= | |
89 | ||
90 | The prototype of the entry/exit callback function is as follows: | |
91 | ||
92 | .. code-block:: c | |
93 | ||
94 | void callback_func(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs); | |
95 | ||
96 | Note that both entry and exit callbacks have same ptototype. The @entry_ip is | |
97 | saved at function entry and passed to exit handler. | |
98 | ||
99 | @fp | |
100 | This is the address of `fprobe` data structure related to this handler. | |
101 | You can embed the `fprobe` to your data structure and get it by | |
102 | container_of() macro from @fp. The @fp must not be NULL. | |
103 | ||
104 | @entry_ip | |
105 | This is the ftrace address of the traced function (both entry and exit). | |
106 | Note that this may not be the actual entry address of the function but | |
107 | the address where the ftrace is instrumented. | |
108 | ||
109 | @regs | |
110 | This is the `pt_regs` data structure at the entry and exit. Note that | |
111 | the instruction pointer of @regs may be different from the @entry_ip | |
112 | in the entry_handler. If you need traced instruction pointer, you need | |
113 | to use @entry_ip. On the other hand, in the exit_handler, the instruction | |
114 | pointer of @regs is set to the currect return address. | |
115 | ||
116 | Share the callbacks with kprobes | |
117 | ================================ | |
118 | ||
119 | Since the recursion safeness of the fprobe (and ftrace) is a bit different | |
120 | from the kprobes, this may cause an issue if user wants to run the same | |
121 | code from the fprobe and the kprobes. | |
122 | ||
123 | Kprobes has per-cpu 'current_kprobe' variable which protects the kprobe | |
124 | handler from recursion in all cases. On the other hand, fprobe uses | |
125 | only ftrace_test_recursion_trylock(). This allows interrupt context to | |
126 | call another (or same) fprobe while the fprobe user handler is running. | |
127 | ||
128 | This is not a matter if the common callback code has its own recursion | |
129 | detection, or it can handle the recursion in the different contexts | |
130 | (normal/interrupt/NMI.) | |
131 | But if it relies on the 'current_kprobe' recursion lock, it has to check | |
132 | kprobe_running() and use kprobe_busy_*() APIs. | |
133 | ||
134 | Fprobe has FPROBE_FL_KPROBE_SHARED flag to do this. If your common callback | |
135 | code will be shared with kprobes, please set FPROBE_FL_KPROBE_SHARED | |
136 | *before* registering the fprobe, like: | |
137 | ||
138 | .. code-block:: c | |
139 | ||
140 | fprobe.flags = FPROBE_FL_KPROBE_SHARED; | |
141 | ||
142 | register_fprobe(&fprobe, "func*", NULL); | |
143 | ||
144 | This will protect your common callback from the nested call. | |
145 | ||
146 | The missed counter | |
147 | ================== | |
148 | ||
149 | The `fprobe` data structure has `fprobe::nmissed` counter field as same as | |
150 | kprobes. | |
151 | This counter counts up when; | |
152 | ||
153 | - fprobe fails to take ftrace_recursion lock. This usually means that a function | |
154 | which is traced by other ftrace users is called from the entry_handler. | |
155 | ||
156 | - fprobe fails to setup the function exit because of the shortage of rethook | |
157 | (the shadow stack for hooking the function return.) | |
158 | ||
159 | The `fprobe::nmissed` field counts up in both cases. Therefore, the former | |
160 | skips both of entry and exit callback and the latter skips the exit | |
161 | callback, but in both case the counter will increase by 1. | |
162 | ||
163 | Note that if you set the FTRACE_OPS_FL_RECURSION and/or FTRACE_OPS_FL_RCU to | |
164 | `fprobe::ops::flags` (ftrace_ops::flags) when registering the fprobe, this | |
165 | counter may not work correctly, because ftrace skips the fprobe function which | |
166 | increase the counter. | |
167 | ||
168 | ||
169 | Functions and structures | |
170 | ======================== | |
171 | ||
172 | .. kernel-doc:: include/linux/fprobe.h | |
173 | .. kernel-doc:: kernel/trace/fprobe.c | |
174 |