event-rule: introduce event-rule kprobe
[lttng-tools.git] / src / common / kernel-probe.c
1 /*
2 * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include "lttng/lttng-error.h"
9 #include <assert.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <fcntl.h>
15 #include <lttng/constant.h>
16 #include <lttng/kernel-probe.h>
17 #include <lttng/kernel-probe-internal.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/unistd.h>
21
22 static
23 int lttng_kernel_probe_location_address_serialize(
24 const struct lttng_kernel_probe_location *location,
25 struct lttng_payload *payload);
26
27 static
28 int lttng_kernel_probe_location_symbol_serialize(
29 const struct lttng_kernel_probe_location *location,
30 struct lttng_payload *payload);
31
32 static
33 bool lttng_kernel_probe_location_address_is_equal(
34 const struct lttng_kernel_probe_location *a,
35 const struct lttng_kernel_probe_location *b);
36
37 static
38 bool lttng_kernel_probe_location_symbol_is_equal(
39 const struct lttng_kernel_probe_location *a,
40 const struct lttng_kernel_probe_location *b);
41
42 enum lttng_kernel_probe_location_type lttng_kernel_probe_location_get_type(
43 const struct lttng_kernel_probe_location *location)
44 {
45 return location ? location->type :
46 LTTNG_KERNEL_PROBE_LOCATION_TYPE_UNKNOWN;
47 }
48
49 static
50 void lttng_kernel_probe_location_address_destroy(
51 struct lttng_kernel_probe_location *location)
52 {
53 assert(location);
54 free(location);
55 }
56
57 static
58 void lttng_kernel_probe_location_symbol_destroy(
59 struct lttng_kernel_probe_location *location)
60 {
61 struct lttng_kernel_probe_location_symbol *location_symbol = NULL;
62
63 assert(location);
64
65 location_symbol = container_of(location,
66 struct lttng_kernel_probe_location_symbol,
67 parent);
68
69 assert(location_symbol);
70
71 free(location_symbol->symbol_name);
72 free(location);
73 }
74
75 void lttng_kernel_probe_location_destroy(
76 struct lttng_kernel_probe_location *location)
77 {
78 if (!location) {
79 return;
80 }
81
82 switch (location->type) {
83 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
84 lttng_kernel_probe_location_address_destroy(location);
85 break;
86 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
87 lttng_kernel_probe_location_symbol_destroy(location);
88 break;
89 default:
90 abort();
91 }
92 }
93
94 struct lttng_kernel_probe_location *
95 lttng_kernel_probe_location_address_create(uint64_t address)
96 {
97 struct lttng_kernel_probe_location *ret = NULL;
98 struct lttng_kernel_probe_location_address *location;
99
100 location = zmalloc(sizeof(*location));
101 if (!location) {
102 PERROR("Error allocating userspace probe location.");
103 goto end;
104 }
105
106 location->address = address;
107
108 ret = &location->parent;
109 ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS;
110 ret->equal = lttng_kernel_probe_location_address_is_equal;
111 ret->serialize = lttng_kernel_probe_location_address_serialize;
112
113 end:
114 return ret;
115 }
116
117 struct lttng_kernel_probe_location *
118 lttng_kernel_probe_location_symbol_create(const char *symbol_name,
119 uint64_t offset)
120 {
121 char *symbol_name_copy = NULL;
122 struct lttng_kernel_probe_location *ret = NULL;
123 struct lttng_kernel_probe_location_symbol *location;
124
125 if (!symbol_name || strlen(symbol_name) >= LTTNG_SYMBOL_NAME_LEN) {
126 goto error;
127 }
128
129 symbol_name_copy = strdup(symbol_name);
130 if (!symbol_name_copy) {
131 PERROR("Failed to copy symbol name '%s'", symbol_name);
132 goto error;
133 }
134
135 location = zmalloc(sizeof(*location));
136 if (!location) {
137 PERROR("Failed to allocate kernel symbol probe location");
138 goto error;
139 }
140
141 location->symbol_name = symbol_name_copy;
142 location->offset = offset;
143
144 ret = &location->parent;
145 ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET;
146 ret->equal = lttng_kernel_probe_location_symbol_is_equal;
147 ret->serialize = lttng_kernel_probe_location_symbol_serialize;
148 goto end;
149
150 error:
151 free(symbol_name_copy);
152 end:
153 return ret;
154 }
155
156 enum lttng_kernel_probe_location_status
157 lttng_kernel_probe_location_address_get_address(
158 const struct lttng_kernel_probe_location *location,
159 uint64_t *offset)
160 {
161 enum lttng_kernel_probe_location_status ret =
162 LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK;
163 struct lttng_kernel_probe_location_address *address_location;
164
165 assert(offset);
166
167 if (!location || lttng_kernel_probe_location_get_type(location) !=
168 LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS) {
169 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
170 ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID;
171 goto end;
172 }
173
174 address_location = container_of(location,
175 struct lttng_kernel_probe_location_address, parent);
176 *offset = address_location->address;
177 end:
178 return ret;
179 }
180
181 const char *lttng_kernel_probe_location_symbol_get_name(
182 const struct lttng_kernel_probe_location *location)
183 {
184 const char *ret = NULL;
185 struct lttng_kernel_probe_location_symbol *symbol_location;
186
187 if (!location || lttng_kernel_probe_location_get_type(location) !=
188 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) {
189 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
190 goto end;
191 }
192
193 symbol_location = container_of(location,
194 struct lttng_kernel_probe_location_symbol, parent);
195 ret = symbol_location->symbol_name;
196 end:
197 return ret;
198 }
199
200 enum lttng_kernel_probe_location_status
201 lttng_kernel_probe_location_symbol_get_offset(
202 const struct lttng_kernel_probe_location *location,
203 uint64_t *offset)
204 {
205 enum lttng_kernel_probe_location_status ret =
206 LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK;
207 struct lttng_kernel_probe_location_symbol *symbol_location;
208
209 assert(offset);
210
211 if (!location || lttng_kernel_probe_location_get_type(location) !=
212 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) {
213 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
214 ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID;
215 goto end;
216 }
217
218 symbol_location = container_of(location,
219 struct lttng_kernel_probe_location_symbol, parent);
220 *offset = symbol_location->offset;
221 end:
222 return ret;
223 }
224
225 static
226 int lttng_kernel_probe_location_symbol_serialize(
227 const struct lttng_kernel_probe_location *location,
228 struct lttng_payload *payload)
229 {
230 int ret;
231 size_t symbol_name_len;
232 size_t original_payload_size;
233 struct lttng_kernel_probe_location_symbol *location_symbol;
234 struct lttng_kernel_probe_location_symbol_comm location_symbol_comm;
235
236 if (!location || !payload) {
237 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
238 ret = -LTTNG_ERR_INVALID;
239 goto end;
240 }
241
242 assert(lttng_kernel_probe_location_get_type(location) ==
243 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
244
245 original_payload_size = payload->buffer.size;
246 location_symbol = container_of(location,
247 struct lttng_kernel_probe_location_symbol, parent);
248
249 if (!location_symbol->symbol_name) {
250 ret = -LTTNG_ERR_INVALID;
251 goto end;
252 }
253
254 symbol_name_len = strlen(location_symbol->symbol_name);
255 if (symbol_name_len == 0) {
256 ret = -LTTNG_ERR_INVALID;
257 goto end;
258 }
259
260 location_symbol_comm.symbol_len = symbol_name_len + 1;
261 location_symbol_comm.offset = location_symbol->offset;
262
263 ret = lttng_dynamic_buffer_append(&payload->buffer,
264 &location_symbol_comm, sizeof(location_symbol_comm));
265 if (ret) {
266 ret = -LTTNG_ERR_INVALID;
267 goto end;
268 }
269
270 ret = lttng_dynamic_buffer_append(&payload->buffer,
271 location_symbol->symbol_name,
272 location_symbol_comm.symbol_len);
273 if (ret) {
274 ret = -LTTNG_ERR_INVALID;
275 goto end;
276 }
277
278 ret = (int) (payload->buffer.size - original_payload_size);
279 end:
280 return ret;
281 }
282
283 static
284 int lttng_kernel_probe_location_address_serialize(
285 const struct lttng_kernel_probe_location *location,
286 struct lttng_payload *payload)
287 {
288 int ret;
289 size_t original_payload_size;
290 struct lttng_kernel_probe_location_address *location_address;
291 struct lttng_kernel_probe_location_address_comm location_address_comm;
292
293 assert(location);
294 assert(lttng_kernel_probe_location_get_type(location) ==
295 LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
296
297 original_payload_size = payload->buffer.size;
298 location_address = container_of(location,
299 struct lttng_kernel_probe_location_address,
300 parent);
301
302 location_address_comm.address = location_address->address;
303
304 ret = lttng_dynamic_buffer_append(&payload->buffer,
305 &location_address_comm,
306 sizeof(location_address_comm));
307 if (ret) {
308 ret = -LTTNG_ERR_INVALID;
309 goto end;
310 }
311
312 ret = (int) (payload->buffer.size - original_payload_size);
313 end:
314 return ret;
315 }
316
317 LTTNG_HIDDEN
318 int lttng_kernel_probe_location_serialize(
319 const struct lttng_kernel_probe_location *location,
320 struct lttng_payload *payload)
321 {
322 int ret;
323 size_t original_payload_size;
324 struct lttng_kernel_probe_location_comm location_generic_comm = {};
325
326 if (!location || !payload) {
327 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
328 ret = -LTTNG_ERR_INVALID;
329 goto end;
330 }
331
332 original_payload_size = payload->buffer.size;
333 location_generic_comm.type = (int8_t) location->type;
334 ret = lttng_dynamic_buffer_append(&payload->buffer,
335 &location_generic_comm,
336 sizeof(location_generic_comm));
337 if (ret) {
338 goto end;
339 }
340
341 ret = location->serialize(location, payload);
342 if (ret < 0) {
343 goto end;
344 }
345
346 ret = (int) (payload->buffer.size - original_payload_size);
347 end:
348 return ret;
349 }
350
351 static
352 int lttng_kernel_probe_location_symbol_create_from_payload(
353 struct lttng_payload_view *view,
354 struct lttng_kernel_probe_location **location)
355 {
356 struct lttng_kernel_probe_location_symbol_comm *location_symbol_comm;
357 const char *symbol_name_src;
358 ssize_t ret = 0;
359 size_t expected_size;
360
361 assert(location);
362
363 if (view->buffer.size < sizeof(*location_symbol_comm)) {
364 ret = -LTTNG_ERR_INVALID;
365 goto end;
366 }
367
368 location_symbol_comm =
369 (typeof(location_symbol_comm)) view->buffer.data;
370
371 expected_size = sizeof(*location_symbol_comm) +
372 location_symbol_comm->symbol_len;
373
374 if (view->buffer.size < expected_size) {
375 ret = -LTTNG_ERR_INVALID;
376 goto end;
377 }
378
379 symbol_name_src = view->buffer.data + sizeof(*location_symbol_comm);
380
381 if (!lttng_buffer_view_contains_string(&view->buffer, symbol_name_src,
382 location_symbol_comm->symbol_len)) {
383 ret = -LTTNG_ERR_INVALID;
384 goto end;
385 }
386
387 *location = lttng_kernel_probe_location_symbol_create(
388 symbol_name_src, location_symbol_comm->offset);
389 if (!(*location)) {
390 ret = -LTTNG_ERR_INVALID;
391 goto end;
392 }
393
394 ret = (ssize_t) expected_size;
395 end:
396 return ret;
397 }
398
399 static
400 ssize_t lttng_kernel_probe_location_address_create_from_payload(
401 struct lttng_payload_view *view,
402 struct lttng_kernel_probe_location **location)
403 {
404 struct lttng_kernel_probe_location_address_comm *location_address_comm;
405 ssize_t ret = 0;
406 size_t expected_size;
407
408 assert(location);
409
410 expected_size = sizeof(*location_address_comm);
411
412 if (view->buffer.size < expected_size) {
413 ret = -LTTNG_ERR_INVALID;
414 goto end;
415 }
416
417 location_address_comm =
418 (typeof(location_address_comm)) view->buffer.data;
419
420 *location = lttng_kernel_probe_location_address_create(location_address_comm->address);
421 if (!(*location)) {
422 ret = -LTTNG_ERR_INVALID;
423 goto end;
424 }
425
426 ret = (size_t) expected_size;
427 end:
428 return ret;
429 }
430
431 LTTNG_HIDDEN
432 ssize_t lttng_kernel_probe_location_create_from_payload(
433 struct lttng_payload_view *view,
434 struct lttng_kernel_probe_location **location)
435 {
436 struct lttng_kernel_probe_location_comm *probe_location_comm;
437 enum lttng_kernel_probe_location_type type;
438 ssize_t consumed = 0;
439 ssize_t ret;
440
441 assert(view);
442 assert(location);
443
444 if (view->buffer.size <= sizeof(*probe_location_comm)) {
445 ret = -LTTNG_ERR_INVALID;
446 goto end;
447 }
448
449 probe_location_comm = (typeof(probe_location_comm)) view->buffer.data;
450 type = (enum lttng_kernel_probe_location_type) probe_location_comm->type;
451 consumed += sizeof(*probe_location_comm);
452
453 switch (type) {
454 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
455 {
456 struct lttng_payload_view location_view =
457 lttng_payload_view_from_view(
458 view, consumed, -1);
459
460 ret = lttng_kernel_probe_location_symbol_create_from_payload(
461 &location_view, location);
462 break;
463 }
464 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
465 {
466 struct lttng_payload_view location_view =
467 lttng_payload_view_from_view(view, consumed, -1);
468
469 ret = lttng_kernel_probe_location_address_create_from_payload(
470 &location_view, location);
471 break;
472 }
473 default:
474 ret = -LTTNG_ERR_INVALID;
475 break;
476 }
477
478 if (ret < 0) {
479 ret = -LTTNG_ERR_INVALID;
480 goto end;
481 }
482
483 ret += consumed;
484
485 end:
486 return ret;
487 }
488
489 static
490 bool lttng_kernel_probe_location_address_is_equal(
491 const struct lttng_kernel_probe_location *_a,
492 const struct lttng_kernel_probe_location *_b)
493 {
494 bool is_equal = false;
495 struct lttng_kernel_probe_location_address *a, *b;
496
497 a = container_of(_a, struct lttng_kernel_probe_location_address,
498 parent);
499 b = container_of(_b, struct lttng_kernel_probe_location_address,
500 parent);
501
502 if (a->address != b->address) {
503 goto end;
504 }
505
506 is_equal = true;
507
508 end:
509 return is_equal;
510 }
511
512 static
513 bool lttng_kernel_probe_location_symbol_is_equal(
514 const struct lttng_kernel_probe_location *_a,
515 const struct lttng_kernel_probe_location *_b)
516 {
517 bool is_equal = false;
518 struct lttng_kernel_probe_location_symbol *a, *b;
519
520 a = container_of(_a, struct lttng_kernel_probe_location_symbol,
521 parent);
522 b = container_of(_b, struct lttng_kernel_probe_location_symbol,
523 parent);
524
525 assert(a->symbol_name);
526 assert(b->symbol_name);
527 if (strcmp(a->symbol_name, b->symbol_name)) {
528 goto end;
529 }
530
531 if (a->offset != b->offset) {
532 goto end;
533 }
534
535 is_equal = true;
536
537 end:
538 return is_equal;
539 }
540
541 LTTNG_HIDDEN
542 bool lttng_kernel_probe_location_is_equal(
543 const struct lttng_kernel_probe_location *a,
544 const struct lttng_kernel_probe_location *b)
545 {
546 bool is_equal = false;
547
548 if (!a || !b) {
549 goto end;
550 }
551
552 if (a == b) {
553 is_equal = true;
554 goto end;
555 }
556
557 if (a->type != b->type) {
558 goto end;
559 }
560
561 is_equal = a->equal ? a->equal(a, b) : true;
562 end:
563 return is_equal;
564 }
565
566 static struct lttng_kernel_probe_location *
567 lttng_kernel_probe_location_symbol_copy(
568 const struct lttng_kernel_probe_location *location)
569 {
570 struct lttng_kernel_probe_location *new_location = NULL;
571 struct lttng_kernel_probe_location_symbol *symbol_location;
572 enum lttng_kernel_probe_location_status status;
573 const char *symbol_name = NULL;
574 uint64_t offset;
575
576 assert(location);
577 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
578 symbol_location = container_of(
579 location, typeof(*symbol_location), parent);
580
581 /* Get probe location offset */
582 status = lttng_kernel_probe_location_symbol_get_offset(location, &offset);
583 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
584 ERR("Get kernel probe location offset failed.");
585 goto error;
586 }
587
588 symbol_name = lttng_kernel_probe_location_symbol_get_name(location);
589 if (!symbol_name) {
590 ERR("Kernel probe symbol name is NULL.");
591 goto error;
592 }
593
594 /* Create the probe_location */
595 new_location = lttng_kernel_probe_location_symbol_create(
596 symbol_name, offset);
597
598 goto end;
599
600 error:
601 new_location = NULL;
602 end:
603 return new_location;
604 }
605 static struct lttng_kernel_probe_location *
606 lttng_kernel_probe_location_address_copy(
607 const struct lttng_kernel_probe_location *location)
608 {
609 struct lttng_kernel_probe_location *new_location = NULL;
610 struct lttng_kernel_probe_location_address *address_location;
611 enum lttng_kernel_probe_location_status status;
612 uint64_t address;
613
614 assert(location);
615 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
616 address_location = container_of(
617 location, typeof(*address_location), parent);
618
619
620 /* Get probe location fields */
621 status = lttng_kernel_probe_location_address_get_address(location, &address);
622 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
623 ERR("Get kernel probe address failed.");
624 goto error;
625 }
626
627 /* Create the probe_location */
628 new_location = lttng_kernel_probe_location_address_create(address);
629
630 goto end;
631
632 error:
633 new_location = NULL;
634 end:
635 return new_location;
636 }
637
638 LTTNG_HIDDEN
639 struct lttng_kernel_probe_location *lttng_kernel_probe_location_copy(
640 const struct lttng_kernel_probe_location *location)
641 {
642 struct lttng_kernel_probe_location *new_location = NULL;
643 enum lttng_kernel_probe_location_type type;
644
645 if (!location) {
646 goto err;
647 }
648
649 type = lttng_kernel_probe_location_get_type(location);
650 switch (type) {
651 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
652 new_location =
653 lttng_kernel_probe_location_address_copy(location);
654 if (!new_location) {
655 goto err;
656 }
657 break;
658 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
659 new_location =
660 lttng_kernel_probe_location_symbol_copy(location);
661 if (!new_location) {
662 goto err;
663 }
664 break;
665 default:
666 new_location = NULL;
667 goto err;
668 }
669 err:
670 return new_location;
671 }
This page took 0.066434 seconds and 4 git commands to generate.