Rename C++ header files to .hpp
[lttng-tools.git] / src / common / event-rule / kernel-uprobe.cpp
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 <common/credentials.hpp>
9 #include <common/error.hpp>
10 #include <common/hashtable/hashtable.hpp>
11 #include <common/hashtable/utils.hpp>
12 #include <common/macros.hpp>
13 #include <common/mi-lttng.hpp>
14 #include <common/payload-view.hpp>
15 #include <common/payload.hpp>
16 #include <common/runas.hpp>
17 #include <lttng/event-rule/event-rule-internal.hpp>
18 #include <lttng/event-rule/kernel-uprobe-internal.hpp>
19 #include <lttng/userspace-probe-internal.hpp>
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 LTTNG_ASSERT(a->name);
130 LTTNG_ASSERT(b->name);
131 if (strcmp(a->name, b->name)) {
132 goto end;
133 }
134
135 LTTNG_ASSERT(a->location);
136 LTTNG_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 __attribute__((unused)),
145 const struct lttng_credentials *creds __attribute__((unused)))
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 __attribute__((unused)))
153 {
154 /* Unsupported. */
155 return NULL;
156 }
157
158 static const struct lttng_bytecode *
159 lttng_event_rule_kernel_uprobe_get_filter_bytecode(
160 const struct lttng_event_rule *rule __attribute__((unused)))
161 {
162 /* Unsupported. */
163 return NULL;
164 }
165
166 static enum lttng_event_rule_generate_exclusions_status
167 lttng_event_rule_kernel_uprobe_generate_exclusions(
168 const struct lttng_event_rule *rule __attribute__((unused)),
169 struct lttng_event_exclusion **exclusions)
170 {
171 /* Unsupported. */
172 *exclusions = NULL;
173 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
174 }
175
176 static unsigned long
177 lttng_event_rule_kernel_uprobe_hash(
178 const struct lttng_event_rule *rule)
179 {
180 unsigned long hash;
181 struct lttng_event_rule_kernel_uprobe *urule =
182 container_of(rule, typeof(*urule), parent);
183
184 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE,
185 lttng_ht_seed);
186 hash ^= hash_key_str(urule->name, lttng_ht_seed);
187 hash ^= lttng_userspace_probe_location_hash(urule->location);
188
189 return hash;
190 }
191
192 static
193 int userspace_probe_set_location(
194 struct lttng_event_rule_kernel_uprobe *uprobe,
195 const struct lttng_userspace_probe_location *location)
196 {
197 int ret;
198 struct lttng_userspace_probe_location *location_copy = NULL;
199
200 if (!uprobe || !location || uprobe->location) {
201 ret = -1;
202 goto end;
203 }
204
205 location_copy = lttng_userspace_probe_location_copy(location);
206 if (!location_copy) {
207 ret = -1;
208 goto end;
209 }
210
211 uprobe->location = location_copy;
212 location_copy = NULL;
213 ret = 0;
214 end:
215 lttng_userspace_probe_location_destroy(location_copy);
216 return ret;
217 }
218
219 static enum lttng_error_code lttng_event_rule_kernel_uprobe_mi_serialize(
220 const struct lttng_event_rule *rule, struct mi_writer *writer)
221 {
222 int ret;
223 enum lttng_error_code ret_code;
224 enum lttng_event_rule_status status;
225 const char *event_name = NULL;
226 const struct lttng_userspace_probe_location *location = NULL;
227
228 LTTNG_ASSERT(rule);
229 LTTNG_ASSERT(writer);
230 LTTNG_ASSERT(IS_UPROBE_EVENT_RULE(rule));
231
232 status = lttng_event_rule_kernel_uprobe_get_event_name(
233 rule, &event_name);
234 LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
235 LTTNG_ASSERT(event_name);
236
237 status = lttng_event_rule_kernel_uprobe_get_location(rule, &location);
238 LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
239 LTTNG_ASSERT(location);
240
241 /* Open event rule kernel uprobe element. */
242 ret = mi_lttng_writer_open_element(
243 writer, mi_lttng_element_event_rule_kernel_uprobe);
244 if (ret) {
245 goto mi_error;
246 }
247
248 /* Event name. */
249 ret = mi_lttng_writer_write_element_string(writer,
250 mi_lttng_element_event_rule_event_name, event_name);
251 if (ret) {
252 goto mi_error;
253 }
254
255 /* Probe location. */
256 ret_code = lttng_userspace_probe_location_mi_serialize(location, writer);
257 if (ret_code != LTTNG_OK) {
258 goto end;
259 }
260
261 /* Close event rule kernel uprobe element. */
262 ret = mi_lttng_writer_close_element(writer);
263 if (ret) {
264 goto mi_error;
265 }
266
267 ret_code = LTTNG_OK;
268 goto end;
269
270 mi_error:
271 ret_code = LTTNG_ERR_MI_IO_FAIL;
272 end:
273 return ret_code;
274 }
275
276 struct lttng_event_rule *lttng_event_rule_kernel_uprobe_create(
277 const struct lttng_userspace_probe_location *location)
278 {
279 struct lttng_event_rule *rule = NULL;
280 struct lttng_event_rule_kernel_uprobe *urule;
281
282 urule = (lttng_event_rule_kernel_uprobe *) zmalloc(sizeof(struct lttng_event_rule_kernel_uprobe));
283 if (!urule) {
284 goto end;
285 }
286
287 rule = &urule->parent;
288 lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
289 urule->parent.validate = lttng_event_rule_kernel_uprobe_validate;
290 urule->parent.serialize = lttng_event_rule_kernel_uprobe_serialize;
291 urule->parent.equal = lttng_event_rule_kernel_uprobe_is_equal;
292 urule->parent.destroy = lttng_event_rule_kernel_uprobe_destroy;
293 urule->parent.generate_filter_bytecode =
294 lttng_event_rule_kernel_uprobe_generate_filter_bytecode;
295 urule->parent.get_filter = lttng_event_rule_kernel_uprobe_get_filter;
296 urule->parent.get_filter_bytecode =
297 lttng_event_rule_kernel_uprobe_get_filter_bytecode;
298 urule->parent.generate_exclusions =
299 lttng_event_rule_kernel_uprobe_generate_exclusions;
300 urule->parent.hash = lttng_event_rule_kernel_uprobe_hash;
301 urule->parent.mi_serialize = lttng_event_rule_kernel_uprobe_mi_serialize;
302
303 if (userspace_probe_set_location(urule, location)) {
304 lttng_event_rule_destroy(rule);
305 rule = NULL;
306 }
307
308 end:
309 return rule;
310 }
311
312 ssize_t lttng_event_rule_kernel_uprobe_create_from_payload(
313 struct lttng_payload_view *view,
314 struct lttng_event_rule **_event_rule)
315 {
316 ssize_t ret, offset = 0;
317 const struct lttng_event_rule_kernel_uprobe_comm *uprobe_comm;
318 const char *name;
319 struct lttng_buffer_view current_buffer_view;
320 struct lttng_event_rule *rule = NULL;
321 struct lttng_userspace_probe_location *location = NULL;
322 enum lttng_event_rule_status status;
323
324 if (!_event_rule) {
325 ret = -1;
326 goto end;
327 }
328
329 current_buffer_view = lttng_buffer_view_from_view(
330 &view->buffer, offset, sizeof(*uprobe_comm));
331 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
332 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
333 ret = -1;
334 goto end;
335 }
336
337 uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
338
339 /* Skip to payload. */
340 offset += current_buffer_view.size;
341
342 /* Map the name. */
343 current_buffer_view = lttng_buffer_view_from_view(
344 &view->buffer, offset, uprobe_comm->name_len);
345 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
346 ret = -1;
347 goto end;
348 }
349
350 name = current_buffer_view.data;
351 if (!lttng_buffer_view_contains_string(&current_buffer_view, name,
352 uprobe_comm->name_len)) {
353 ret = -1;
354 goto end;
355 }
356
357 /* Skip after the name. */
358 offset += uprobe_comm->name_len;
359
360 /* Map the location. */
361 {
362 struct lttng_payload_view current_payload_view =
363 lttng_payload_view_from_view(view, offset,
364 uprobe_comm->location_len);
365
366 if (!lttng_payload_view_is_valid(&current_payload_view)) {
367 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
368 ret = -1;
369 goto end;
370 }
371
372 ret = lttng_userspace_probe_location_create_from_payload(
373 &current_payload_view, &location);
374 if (ret < 0) {
375 ret = -1;
376 goto end;
377 }
378 }
379
380 LTTNG_ASSERT(ret == uprobe_comm->location_len);
381
382 /* Skip after the location. */
383 offset += uprobe_comm->location_len;
384
385 rule = lttng_event_rule_kernel_uprobe_create(location);
386 if (!rule) {
387 ERR("Failed to create event rule uprobe.");
388 ret = -1;
389 goto end;
390 }
391
392 status = lttng_event_rule_kernel_uprobe_set_event_name(rule, name);
393 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
394 ret = -1;
395 goto end;
396 }
397
398 if (!lttng_event_rule_kernel_uprobe_validate(rule)) {
399 ret = -1;
400 goto end;
401 }
402
403 *_event_rule = rule;
404 rule = NULL;
405 ret = offset;
406 end:
407 lttng_userspace_probe_location_destroy(location);
408 lttng_event_rule_destroy(rule);
409 return ret;
410 }
411
412
413 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_get_location(
414 const struct lttng_event_rule *rule,
415 const struct lttng_userspace_probe_location **location)
416 {
417 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
418
419 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
420 status = LTTNG_EVENT_RULE_STATUS_INVALID;
421 goto end;
422 }
423
424 *location = lttng_event_rule_kernel_uprobe_get_location_mutable(rule);
425 if (!*location) {
426 status = LTTNG_EVENT_RULE_STATUS_UNSET;
427 goto end;
428 }
429
430 end:
431 return status;
432 }
433
434 struct lttng_userspace_probe_location *
435 lttng_event_rule_kernel_uprobe_get_location_mutable(
436 const struct lttng_event_rule *rule)
437 {
438 struct lttng_event_rule_kernel_uprobe *uprobe;
439
440 LTTNG_ASSERT(rule);
441 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
442
443 return uprobe->location;
444 }
445
446 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_set_event_name(
447 struct lttng_event_rule *rule, const char *name)
448 {
449 char *name_copy = NULL;
450 struct lttng_event_rule_kernel_uprobe *uprobe;
451 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
452
453 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name ||
454 strlen(name) == 0) {
455 status = LTTNG_EVENT_RULE_STATUS_INVALID;
456 goto end;
457 }
458
459 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
460 name_copy = strdup(name);
461 if (!name_copy) {
462 status = LTTNG_EVENT_RULE_STATUS_ERROR;
463 goto end;
464 }
465
466 if (uprobe->name) {
467 free(uprobe->name);
468 }
469
470 uprobe->name = name_copy;
471 name_copy = NULL;
472 end:
473 return status;
474 }
475
476 enum lttng_event_rule_status lttng_event_rule_kernel_uprobe_get_event_name(
477 const struct lttng_event_rule *rule, const char **name)
478 {
479 struct lttng_event_rule_kernel_uprobe *uprobe;
480 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
481
482 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
483 status = LTTNG_EVENT_RULE_STATUS_INVALID;
484 goto end;
485 }
486
487 uprobe = container_of(rule, struct lttng_event_rule_kernel_uprobe, parent);
488 if (!uprobe->name) {
489 status = LTTNG_EVENT_RULE_STATUS_UNSET;
490 goto end;
491 }
492
493 *name = uprobe->name;
494 end:
495 return status;
496 }
This page took 0.039062 seconds and 4 git commands to generate.