]>
Commit | Line | Data |
---|---|---|
64836248 TZ |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Test module for in-kernel kprobe event creation and generation. | |
4 | * | |
5 | * Copyright (C) 2019 Tom Zanussi <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <linux/module.h> | |
9 | #include <linux/trace_events.h> | |
10 | ||
11 | /* | |
12 | * This module is a simple test of basic functionality for in-kernel | |
13 | * kprobe/kretprobe event creation. The first test uses | |
14 | * kprobe_event_gen_cmd_start(), kprobe_event_add_fields() and | |
15 | * kprobe_event_gen_cmd_end() to create a kprobe event, which is then | |
16 | * enabled in order to generate trace output. The second creates a | |
17 | * kretprobe event using kretprobe_event_gen_cmd_start() and | |
18 | * kretprobe_event_gen_cmd_end(), and is also then enabled. | |
19 | * | |
20 | * To test, select CONFIG_KPROBE_EVENT_GEN_TEST and build the module. | |
21 | * Then: | |
22 | * | |
23 | * # insmod kernel/trace/kprobe_event_gen_test.ko | |
24 | * # cat /sys/kernel/debug/tracing/trace | |
25 | * | |
26 | * You should see many instances of the "gen_kprobe_test" and | |
27 | * "gen_kretprobe_test" events in the trace buffer. | |
28 | * | |
29 | * To remove the events, remove the module: | |
30 | * | |
31 | * # rmmod kprobe_event_gen_test | |
32 | * | |
33 | */ | |
34 | ||
35 | static struct trace_event_file *gen_kprobe_test; | |
36 | static struct trace_event_file *gen_kretprobe_test; | |
37 | ||
38 | /* | |
39 | * Test to make sure we can create a kprobe event, then add more | |
40 | * fields. | |
41 | */ | |
42 | static int __init test_gen_kprobe_cmd(void) | |
43 | { | |
44 | struct dynevent_cmd cmd; | |
45 | char *buf; | |
46 | int ret; | |
47 | ||
48 | /* Create a buffer to hold the generated command */ | |
49 | buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL); | |
50 | if (!buf) | |
51 | return -ENOMEM; | |
52 | ||
53 | /* Before generating the command, initialize the cmd object */ | |
54 | kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN); | |
55 | ||
56 | /* | |
57 | * Define the gen_kprobe_test event with the first 2 kprobe | |
58 | * fields. | |
59 | */ | |
60 | ret = kprobe_event_gen_cmd_start(&cmd, "gen_kprobe_test", | |
61 | "do_sys_open", | |
62 | "dfd=%ax", "filename=%dx"); | |
63 | if (ret) | |
64 | goto free; | |
65 | ||
66 | /* Use kprobe_event_add_fields to add the rest of the fields */ | |
67 | ||
68 | ret = kprobe_event_add_fields(&cmd, "flags=%cx", "mode=+4($stack)"); | |
69 | if (ret) | |
70 | goto free; | |
71 | ||
72 | /* | |
73 | * This actually creates the event. | |
74 | */ | |
75 | ret = kprobe_event_gen_cmd_end(&cmd); | |
76 | if (ret) | |
77 | goto free; | |
78 | ||
79 | /* | |
80 | * Now get the gen_kprobe_test event file. We need to prevent | |
81 | * the instance and event from disappearing from underneath | |
82 | * us, which trace_get_event_file() does (though in this case | |
83 | * we're using the top-level instance which never goes away). | |
84 | */ | |
85 | gen_kprobe_test = trace_get_event_file(NULL, "kprobes", | |
86 | "gen_kprobe_test"); | |
87 | if (IS_ERR(gen_kprobe_test)) { | |
88 | ret = PTR_ERR(gen_kprobe_test); | |
89 | goto delete; | |
90 | } | |
91 | ||
92 | /* Enable the event or you won't see anything */ | |
93 | ret = trace_array_set_clr_event(gen_kprobe_test->tr, | |
94 | "kprobes", "gen_kprobe_test", true); | |
95 | if (ret) { | |
96 | trace_put_event_file(gen_kprobe_test); | |
97 | goto delete; | |
98 | } | |
99 | out: | |
100 | return ret; | |
101 | delete: | |
102 | /* We got an error after creating the event, delete it */ | |
103 | ret = kprobe_event_delete("gen_kprobe_test"); | |
104 | free: | |
105 | kfree(buf); | |
106 | ||
107 | goto out; | |
108 | } | |
109 | ||
110 | /* | |
111 | * Test to make sure we can create a kretprobe event. | |
112 | */ | |
113 | static int __init test_gen_kretprobe_cmd(void) | |
114 | { | |
115 | struct dynevent_cmd cmd; | |
116 | char *buf; | |
117 | int ret; | |
118 | ||
119 | /* Create a buffer to hold the generated command */ | |
120 | buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL); | |
121 | if (!buf) | |
122 | return -ENOMEM; | |
123 | ||
124 | /* Before generating the command, initialize the cmd object */ | |
125 | kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN); | |
126 | ||
127 | /* | |
128 | * Define the kretprobe event. | |
129 | */ | |
130 | ret = kretprobe_event_gen_cmd_start(&cmd, "gen_kretprobe_test", | |
131 | "do_sys_open", | |
132 | "$retval"); | |
133 | if (ret) | |
134 | goto free; | |
135 | ||
136 | /* | |
137 | * This actually creates the event. | |
138 | */ | |
139 | ret = kretprobe_event_gen_cmd_end(&cmd); | |
140 | if (ret) | |
141 | goto free; | |
142 | ||
143 | /* | |
144 | * Now get the gen_kretprobe_test event file. We need to | |
145 | * prevent the instance and event from disappearing from | |
146 | * underneath us, which trace_get_event_file() does (though in | |
147 | * this case we're using the top-level instance which never | |
148 | * goes away). | |
149 | */ | |
150 | gen_kretprobe_test = trace_get_event_file(NULL, "kprobes", | |
151 | "gen_kretprobe_test"); | |
152 | if (IS_ERR(gen_kretprobe_test)) { | |
153 | ret = PTR_ERR(gen_kretprobe_test); | |
154 | goto delete; | |
155 | } | |
156 | ||
157 | /* Enable the event or you won't see anything */ | |
158 | ret = trace_array_set_clr_event(gen_kretprobe_test->tr, | |
159 | "kprobes", "gen_kretprobe_test", true); | |
160 | if (ret) { | |
161 | trace_put_event_file(gen_kretprobe_test); | |
162 | goto delete; | |
163 | } | |
164 | out: | |
165 | return ret; | |
166 | delete: | |
167 | /* We got an error after creating the event, delete it */ | |
168 | ret = kprobe_event_delete("gen_kretprobe_test"); | |
169 | free: | |
170 | kfree(buf); | |
171 | ||
172 | goto out; | |
173 | } | |
174 | ||
175 | static int __init kprobe_event_gen_test_init(void) | |
176 | { | |
177 | int ret; | |
178 | ||
179 | ret = test_gen_kprobe_cmd(); | |
180 | if (ret) | |
181 | return ret; | |
182 | ||
183 | ret = test_gen_kretprobe_cmd(); | |
184 | if (ret) { | |
185 | WARN_ON(trace_array_set_clr_event(gen_kretprobe_test->tr, | |
186 | "kprobes", | |
187 | "gen_kretprobe_test", false)); | |
188 | trace_put_event_file(gen_kretprobe_test); | |
189 | WARN_ON(kprobe_event_delete("gen_kretprobe_test")); | |
190 | } | |
191 | ||
192 | return ret; | |
193 | } | |
194 | ||
195 | static void __exit kprobe_event_gen_test_exit(void) | |
196 | { | |
197 | /* Disable the event or you can't remove it */ | |
198 | WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr, | |
199 | "kprobes", | |
200 | "gen_kprobe_test", false)); | |
201 | ||
202 | /* Now give the file and instance back */ | |
203 | trace_put_event_file(gen_kprobe_test); | |
204 | ||
205 | /* Now unregister and free the event */ | |
206 | WARN_ON(kprobe_event_delete("gen_kprobe_test")); | |
207 | ||
208 | /* Disable the event or you can't remove it */ | |
209 | WARN_ON(trace_array_set_clr_event(gen_kprobe_test->tr, | |
210 | "kprobes", | |
211 | "gen_kretprobe_test", false)); | |
212 | ||
213 | /* Now give the file and instance back */ | |
214 | trace_put_event_file(gen_kretprobe_test); | |
215 | ||
216 | /* Now unregister and free the event */ | |
217 | WARN_ON(kprobe_event_delete("gen_kretprobe_test")); | |
218 | } | |
219 | ||
220 | module_init(kprobe_event_gen_test_init) | |
221 | module_exit(kprobe_event_gen_test_exit) | |
222 | ||
223 | MODULE_AUTHOR("Tom Zanussi"); | |
224 | MODULE_DESCRIPTION("kprobe event generation test"); | |
225 | MODULE_LICENSE("GPL v2"); |