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