Move event-expr-to-bytecode to event-expr
[lttng-tools.git] / src / common / event-rule / kernel-uprobe.c
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/credentials.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <common/runas.h>
15 #include <common/hashtable/hashtable.h>
16 #include <common/hashtable/utils.h>
17 #include <lttng/event-rule/event-rule-internal.h>
18 #include <lttng/event-rule/kernel-uprobe-internal.h>
19 #include <lttng/userspace-probe-internal.h>
20
21 #define IS_UPROBE_EVENT_RULE(rule) \
22 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE)
23
24 static void lttng_event_rule_kernel_uprobe_destroy(struct lttng_event_rule *rule)
25 {
26 struct lttng_event_rule_kernel_uprobe *uprobe;
27
28 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
29
30 lttng_userspace_probe_location_destroy(uprobe->location);
31 free(uprobe->name);
32 free(uprobe);
33 }
34
35 static bool lttng_event_rule_kernel_uprobe_validate(
36 const struct lttng_event_rule *rule)
37 {
38 bool valid = false;
39 struct lttng_event_rule_kernel_uprobe *uprobe;
40
41 if (!rule) {
42 goto end;
43 }
44
45 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
46
47 /* Required field. */
48 if (!uprobe->name) {
49 ERR("Invalid uprobe event rule: a pattern must be set.");
50 goto end;
51 }
52
53 if (!uprobe->location) {
54 ERR("Invalid uprobe event rule: a location must be set.");
55 goto end;
56 }
57
58 valid = true;
59 end:
60 return valid;
61 }
62
63 static int lttng_event_rule_kernel_uprobe_serialize(
64 const struct lttng_event_rule *rule,
65 struct lttng_payload *payload)
66 {
67 int ret;
68 size_t name_len, header_offset, size_before_probe;
69 struct lttng_event_rule_kernel_uprobe *uprobe;
70 struct lttng_event_rule_kernel_uprobe_comm uprobe_comm = {};
71 struct lttng_event_rule_kernel_uprobe_comm *header;
72
73 if (!rule || !IS_UPROBE_EVENT_RULE(rule)) {
74 ret = -1;
75 goto end;
76 }
77
78 header_offset = payload->buffer.size;
79
80 DBG("Serializing uprobe event rule.");
81 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
82
83 name_len = strlen(uprobe->name) + 1;
84
85 uprobe_comm.name_len = name_len;
86
87 ret = lttng_dynamic_buffer_append(
88 &payload->buffer, &uprobe_comm, sizeof(uprobe_comm));
89 if (ret) {
90 goto end;
91 }
92 ret = lttng_dynamic_buffer_append(
93 &payload->buffer, uprobe->name, name_len);
94 if (ret) {
95 goto end;
96 }
97
98 size_before_probe = payload->buffer.size;
99
100 /* This serialize return the size taken in the buffer. */
101 ret = lttng_userspace_probe_location_serialize(
102 uprobe->location, payload);
103 if (ret < 0) {
104 goto end;
105 }
106
107 /* Update the header regarding the probe size. */
108 header = (struct lttng_event_rule_kernel_uprobe_comm
109 *) ((char *) payload->buffer.data +
110 header_offset);
111 header->location_len = payload->buffer.size - size_before_probe;
112
113 ret = 0;
114
115 end:
116 return ret;
117 }
118
119 static bool lttng_event_rule_kernel_uprobe_is_equal(const struct lttng_event_rule *_a,
120 const struct lttng_event_rule *_b)
121 {
122 bool is_equal = false;
123 struct lttng_event_rule_kernel_uprobe *a, *b;
124
125 a = container_of(_a, struct lttng_event_rule_kernel_uprobe, parent);
126 b = container_of(_b, struct lttng_event_rule_kernel_uprobe, parent);
127
128 /* uprobe is invalid if this is not true. */
129 assert(a->name);
130 assert(b->name);
131 if (strcmp(a->name, b->name)) {
132 goto end;
133 }
134
135 assert(a->location);
136 assert(b->location);
137 is_equal = lttng_userspace_probe_location_is_equal(
138 a->location, b->location);
139 end:
140 return is_equal;
141 }
142
143 static enum lttng_error_code lttng_event_rule_kernel_uprobe_generate_filter_bytecode(
144 struct lttng_event_rule *rule,
145 const struct lttng_credentials *creds)
146 {
147 /* Nothing to do. */
148 return LTTNG_OK;
149 }
150
151 static const char *lttng_event_rule_kernel_uprobe_get_filter(
152 const struct lttng_event_rule *rule)
153 {
154 /* Unsupported. */
155 return NULL;
156 }
157
158 static const struct lttng_bytecode *
159 lttng_event_rule_kernel_uprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
160 {
161 /* Unsupported. */
162 return NULL;
163 }
164
165 static enum lttng_event_rule_generate_exclusions_status
166 lttng_event_rule_kernel_uprobe_generate_exclusions(const struct lttng_event_rule *rule,
167 struct lttng_event_exclusion **exclusions)
168 {
169 /* Unsupported. */
170 *exclusions = NULL;
171 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
172 }
173
174 static unsigned long
175 lttng_event_rule_kernel_uprobe_hash(
176 const struct lttng_event_rule *rule)
177 {
178 unsigned long hash;
179 struct lttng_event_rule_kernel_uprobe *urule =
180 container_of(rule, typeof(*urule), parent);
181
182 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE,
183 lttng_ht_seed);
184 hash ^= hash_key_str(urule->name, lttng_ht_seed);
185 hash ^= lttng_userspace_probe_location_hash(urule->location);
186
187 return hash;
188 }
189
190 static
191 int userspace_probe_set_location(
192 struct lttng_event_rule_kernel_uprobe *uprobe,
193 const struct lttng_userspace_probe_location *location)
194 {
195 int ret;
196 struct lttng_userspace_probe_location *location_copy = NULL;
197
198 if (!uprobe || !location || uprobe->location) {
199 ret = -1;
200 goto end;
201 }
202
203 location_copy = lttng_userspace_probe_location_copy(location);
204 if (!location_copy) {
205 ret = -1;
206 goto end;
207 }
208
209 uprobe->location = location_copy;
210 location_copy = NULL;
211 ret = 0;
212 end:
213 lttng_userspace_probe_location_destroy(location_copy);
214 return ret;
215 }
216
217 struct lttng_event_rule *lttng_event_rule_kernel_uprobe_create(
218 const struct lttng_userspace_probe_location *location)
219 {
220 struct lttng_event_rule *rule = NULL;
221 struct lttng_event_rule_kernel_uprobe *urule;
222
223 urule = zmalloc(sizeof(struct lttng_event_rule_kernel_uprobe));
224 if (!urule) {
225 goto end;
226 }
227
228 rule = &urule->parent;
229 lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
230 urule->parent.validate = lttng_event_rule_kernel_uprobe_validate;
231 urule->parent.serialize = lttng_event_rule_kernel_uprobe_serialize;
232 urule->parent.equal = lttng_event_rule_kernel_uprobe_is_equal;
233 urule->parent.destroy = lttng_event_rule_kernel_uprobe_destroy;
234 urule->parent.generate_filter_bytecode =
235 lttng_event_rule_kernel_uprobe_generate_filter_bytecode;
236 urule->parent.get_filter = lttng_event_rule_kernel_uprobe_get_filter;
237 urule->parent.get_filter_bytecode =
238 lttng_event_rule_kernel_uprobe_get_filter_bytecode;
239 urule->parent.generate_exclusions =
240 lttng_event_rule_kernel_uprobe_generate_exclusions;
241 urule->parent.hash = lttng_event_rule_kernel_uprobe_hash;
242
243 if (userspace_probe_set_location(urule, location)) {
244 lttng_event_rule_destroy(rule);
245 rule = NULL;
246 }
247
248 end:
249 return rule;
250 }
251
252 LTTNG_HIDDEN
253 ssize_t lttng_event_rule_kernel_uprobe_create_from_payload(
254 struct lttng_payload_view *view,
255 struct lttng_event_rule **_event_rule)
256 {
257 ssize_t ret, offset = 0;
258 const struct lttng_event_rule_kernel_uprobe_comm *uprobe_comm;
259 const char *name;
260 struct lttng_buffer_view current_buffer_view;
261 struct lttng_event_rule *rule = NULL;
262 struct lttng_userspace_probe_location *location = NULL;
263 enum lttng_event_rule_status status;
264
265 if (!_event_rule) {
266 ret = -1;
267 goto end;
268 }
269
270 current_buffer_view = lttng_buffer_view_from_view(
271 &view->buffer, offset, sizeof(*uprobe_comm));
272 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
273 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
274 ret = -1;
275 goto end;
276 }
277
278 uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
279
280 /* Skip to payload. */
281 offset += current_buffer_view.size;
282
283 /* Map the name. */
284 current_buffer_view = lttng_buffer_view_from_view(
285 &view->buffer, offset, uprobe_comm->name_len);
286 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
287 ret = -1;
288 goto end;
289 }
290
291 name = current_buffer_view.data;
292 if (!lttng_buffer_view_contains_string(&current_buffer_view, name,
293 uprobe_comm->name_len)) {
294 ret = -1;
295 goto end;
296 }
297
298 /* Skip after the name. */
299 offset += uprobe_comm->name_len;
300
301 /* Map the location. */
302 {
303 struct lttng_payload_view current_payload_view =
304 lttng_payload_view_from_view(view, offset,
305 uprobe_comm->location_len);
306
307 if (!lttng_payload_view_is_valid(&current_payload_view)) {
308 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
309 ret = -1;
310 goto end;
311 }
312
313 ret = lttng_userspace_probe_location_create_from_payload(
314 &current_payload_view, &location);
315 if (ret < 0) {
316 ret = -1;
317 goto end;
318 }
319 }
320
321 assert(ret == uprobe_comm->location_len);
322
323 /* Skip after the location. */
324 offset += uprobe_comm->location_len;
325
326 rule = lttng_event_rule_kernel_uprobe_create(location);
327 if (!rule) {
328 ERR("Failed to create event rule uprobe.");
329 ret = -1;
330 goto end;
331 }
332
333 status = lttng_event_rule_kernel_uprobe_set_event_name(rule, name);
334 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
335 ret = -1;
336 goto end;
337 }
338
339 if (!lttng_event_rule_kernel_uprobe_validate(rule)) {
340 ret = -1;
341 goto end;
342 }
343
344 *_event_rule = rule;
345 rule = NULL;
346 ret = offset;
347 end:
348 lttng_userspace_probe_location_destroy(location);
349 lttng_event_rule_destroy(rule);
350 return ret;
351 }
352
353
354 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_get_location(
355 const struct lttng_event_rule *rule,
356 const struct lttng_userspace_probe_location **location)
357 {
358 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
359
360 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
361 status = LTTNG_EVENT_RULE_STATUS_INVALID;
362 goto end;
363 }
364
365 *location = lttng_event_rule_kernel_uprobe_get_location_mutable(rule);
366 if (!*location) {
367 status = LTTNG_EVENT_RULE_STATUS_UNSET;
368 goto end;
369 }
370
371 end:
372 return status;
373 }
374
375 LTTNG_HIDDEN
376 struct lttng_userspace_probe_location *
377 lttng_event_rule_kernel_uprobe_get_location_mutable(
378 const struct lttng_event_rule *rule)
379 {
380 struct lttng_event_rule_kernel_uprobe *uprobe;
381
382 assert(rule);
383 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
384
385 return uprobe->location;
386 }
387
388 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_set_event_name(
389 struct lttng_event_rule *rule, const char *name)
390 {
391 char *name_copy = NULL;
392 struct lttng_event_rule_kernel_uprobe *uprobe;
393 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
394
395 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name ||
396 strlen(name) == 0) {
397 status = LTTNG_EVENT_RULE_STATUS_INVALID;
398 goto end;
399 }
400
401 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
402 name_copy = strdup(name);
403 if (!name_copy) {
404 status = LTTNG_EVENT_RULE_STATUS_ERROR;
405 goto end;
406 }
407
408 if (uprobe->name) {
409 free(uprobe->name);
410 }
411
412 uprobe->name = name_copy;
413 name_copy = NULL;
414 end:
415 return status;
416 }
417
418 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_get_event_name(
419 const struct lttng_event_rule *rule, const char **name)
420 {
421 struct lttng_event_rule_kernel_uprobe *uprobe;
422 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
423
424 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
425 status = LTTNG_EVENT_RULE_STATUS_INVALID;
426 goto end;
427 }
428
429 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
430 if (!uprobe->name) {
431 status = LTTNG_EVENT_RULE_STATUS_UNSET;
432 goto end;
433 }
434
435 *name = uprobe->name;
436 end:
437 return status;
438 }
This page took 0.04919 seconds and 4 git commands to generate.