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 | ||
8be098a9 | 90 | The prototype of the entry/exit callback function are as follows: |
aba09b44 MH |
91 | |
92 | .. code-block:: c | |
93 | ||
2a86ac30 | 94 | int entry_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct pt_regs *regs, void *entry_data); |
aba09b44 | 95 | |
2a86ac30 | 96 | void exit_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct pt_regs *regs, void *entry_data); |
8be098a9 MHG |
97 | |
98 | Note that the @entry_ip is saved at function entry and passed to exit handler. | |
99 | If the entry callback function returns !0, the corresponding exit callback will be cancelled. | |
aba09b44 MH |
100 | |
101 | @fp | |
102 | This is the address of `fprobe` data structure related to this handler. | |
103 | You can embed the `fprobe` to your data structure and get it by | |
104 | container_of() macro from @fp. The @fp must not be NULL. | |
105 | ||
106 | @entry_ip | |
107 | This is the ftrace address of the traced function (both entry and exit). | |
108 | Note that this may not be the actual entry address of the function but | |
109 | the address where the ftrace is instrumented. | |
110 | ||
2a86ac30 MHG |
111 | @ret_ip |
112 | This is the return address that the traced function will return to, | |
113 | somewhere in the caller. This can be used at both entry and exit. | |
114 | ||
aba09b44 MH |
115 | @regs |
116 | This is the `pt_regs` data structure at the entry and exit. Note that | |
117 | the instruction pointer of @regs may be different from the @entry_ip | |
118 | in the entry_handler. If you need traced instruction pointer, you need | |
119 | to use @entry_ip. On the other hand, in the exit_handler, the instruction | |
d56b699d | 120 | pointer of @regs is set to the current return address. |
aba09b44 | 121 | |
8be098a9 MHG |
122 | @entry_data |
123 | This is a local storage to share the data between entry and exit handlers. | |
124 | This storage is NULL by default. If the user specify `exit_handler` field | |
125 | and `entry_data_size` field when registering the fprobe, the storage is | |
126 | allocated and passed to both `entry_handler` and `exit_handler`. | |
127 | ||
aba09b44 MH |
128 | Share the callbacks with kprobes |
129 | ================================ | |
130 | ||
131 | Since the recursion safeness of the fprobe (and ftrace) is a bit different | |
132 | from the kprobes, this may cause an issue if user wants to run the same | |
133 | code from the fprobe and the kprobes. | |
134 | ||
135 | Kprobes has per-cpu 'current_kprobe' variable which protects the kprobe | |
136 | handler from recursion in all cases. On the other hand, fprobe uses | |
137 | only ftrace_test_recursion_trylock(). This allows interrupt context to | |
138 | call another (or same) fprobe while the fprobe user handler is running. | |
139 | ||
140 | This is not a matter if the common callback code has its own recursion | |
141 | detection, or it can handle the recursion in the different contexts | |
142 | (normal/interrupt/NMI.) | |
143 | But if it relies on the 'current_kprobe' recursion lock, it has to check | |
144 | kprobe_running() and use kprobe_busy_*() APIs. | |
145 | ||
146 | Fprobe has FPROBE_FL_KPROBE_SHARED flag to do this. If your common callback | |
147 | code will be shared with kprobes, please set FPROBE_FL_KPROBE_SHARED | |
148 | *before* registering the fprobe, like: | |
149 | ||
150 | .. code-block:: c | |
151 | ||
152 | fprobe.flags = FPROBE_FL_KPROBE_SHARED; | |
153 | ||
154 | register_fprobe(&fprobe, "func*", NULL); | |
155 | ||
156 | This will protect your common callback from the nested call. | |
157 | ||
158 | The missed counter | |
159 | ================== | |
160 | ||
161 | The `fprobe` data structure has `fprobe::nmissed` counter field as same as | |
162 | kprobes. | |
163 | This counter counts up when; | |
164 | ||
165 | - fprobe fails to take ftrace_recursion lock. This usually means that a function | |
166 | which is traced by other ftrace users is called from the entry_handler. | |
167 | ||
168 | - fprobe fails to setup the function exit because of the shortage of rethook | |
169 | (the shadow stack for hooking the function return.) | |
170 | ||
171 | The `fprobe::nmissed` field counts up in both cases. Therefore, the former | |
172 | skips both of entry and exit callback and the latter skips the exit | |
173 | callback, but in both case the counter will increase by 1. | |
174 | ||
175 | Note that if you set the FTRACE_OPS_FL_RECURSION and/or FTRACE_OPS_FL_RCU to | |
176 | `fprobe::ops::flags` (ftrace_ops::flags) when registering the fprobe, this | |
177 | counter may not work correctly, because ftrace skips the fprobe function which | |
178 | increase the counter. | |
179 | ||
180 | ||
181 | Functions and structures | |
182 | ======================== | |
183 | ||
184 | .. kernel-doc:: include/linux/fprobe.h | |
185 | .. kernel-doc:: kernel/trace/fprobe.c | |
186 |