2ad8bfd919acbd7f05df0ea93bcfb295ea71675b
[lttng-tools.git] / src / common / userspace-probe.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@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/compat/string.h>
11 #include <common/error.h>
12 #include <common/macros.h>
13 #include <common/payload.h>
14 #include <common/payload-view.h>
15 #include <fcntl.h>
16 #include <lttng/constant.h>
17 #include <lttng/userspace-probe-internal.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/unistd.h>
21
22 static
23 int lttng_userspace_probe_location_function_set_binary_fd_handle(
24 struct lttng_userspace_probe_location *location,
25 struct fd_handle *binary_fd_handle);
26
27 static
28 int lttng_userspace_probe_location_tracepoint_set_binary_fd_handle(
29 struct lttng_userspace_probe_location *location,
30 struct fd_handle *binary_fd_handle);
31
32 enum lttng_userspace_probe_location_lookup_method_type
33 lttng_userspace_probe_location_lookup_method_get_type(
34 const struct lttng_userspace_probe_location_lookup_method *lookup_method)
35 {
36 return lookup_method ? lookup_method->type :
37 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_UNKNOWN;
38 }
39
40 void lttng_userspace_probe_location_lookup_method_destroy(
41 struct lttng_userspace_probe_location_lookup_method *lookup_method)
42 {
43 if (!lookup_method){
44 return;
45 }
46
47 free(lookup_method);
48 }
49
50 struct lttng_userspace_probe_location_lookup_method *
51 lttng_userspace_probe_location_lookup_method_function_elf_create(void)
52 {
53 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
54 struct lttng_userspace_probe_location_lookup_method_elf *elf_method;
55
56 elf_method = zmalloc(sizeof(*elf_method));
57 if (!elf_method) {
58 PERROR("zmalloc");
59 goto end;
60 }
61
62 ret = &elf_method->parent;
63 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF;
64 end:
65 return ret;
66 }
67
68 struct lttng_userspace_probe_location_lookup_method *
69 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create(void)
70 {
71 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
72 struct lttng_userspace_probe_location_lookup_method_sdt *sdt_method;
73
74 sdt_method = zmalloc(sizeof(*sdt_method));
75 if (!sdt_method) {
76 PERROR("zmalloc");
77 goto end;
78 }
79
80 ret = &sdt_method->parent;
81 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT;
82 end:
83 return ret;
84 }
85
86 enum lttng_userspace_probe_location_type lttng_userspace_probe_location_get_type(
87 const struct lttng_userspace_probe_location *location)
88 {
89 return location ? location->type :
90 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_UNKNOWN;
91 }
92
93 static
94 void lttng_userspace_probe_location_function_destroy(
95 struct lttng_userspace_probe_location *location)
96 {
97 struct lttng_userspace_probe_location_function *location_function = NULL;
98
99 assert(location);
100
101 location_function = container_of(location,
102 struct lttng_userspace_probe_location_function, parent);
103
104 assert(location_function);
105
106 free(location_function->function_name);
107 free(location_function->binary_path);
108 fd_handle_put(location_function->binary_fd_handle);
109 free(location);
110 }
111
112 static
113 void lttng_userspace_probe_location_tracepoint_destroy(
114 struct lttng_userspace_probe_location *location)
115 {
116 struct lttng_userspace_probe_location_tracepoint *location_tracepoint = NULL;
117
118 assert(location);
119
120 location_tracepoint = container_of(location,
121 struct lttng_userspace_probe_location_tracepoint,
122 parent);
123
124 assert(location_tracepoint);
125
126 free(location_tracepoint->probe_name);
127 free(location_tracepoint->provider_name);
128 free(location_tracepoint->binary_path);
129 fd_handle_put(location_tracepoint->binary_fd_handle);
130 free(location);
131 }
132
133 void lttng_userspace_probe_location_destroy(
134 struct lttng_userspace_probe_location *location)
135 {
136 if (!location) {
137 return;
138 }
139
140 lttng_userspace_probe_location_lookup_method_destroy(
141 location->lookup_method);
142
143 switch (location->type) {
144 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
145 lttng_userspace_probe_location_function_destroy(location);
146 break;
147 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
148 lttng_userspace_probe_location_tracepoint_destroy(location);
149 break;
150 default:
151 abort();
152 }
153 }
154
155 /* Compare two file descriptors based on their inode and device numbers. */
156 static bool fd_is_equal(int a, int b)
157 {
158 int ret;
159 bool is_equal = false;
160 struct stat a_stat, b_stat;
161
162 if (a < 0 && b >= 0) {
163 goto end;
164 }
165
166 if (b < 0 && a >= 0) {
167 goto end;
168 }
169
170 if (a < 0 && b < 0) {
171 if (a == -1 && b == -1) {
172 is_equal = true;
173 goto end;
174 }
175
176 /* Invalid state, abort. */
177 abort();
178 }
179
180 /* Both are valid file descriptors. */
181 ret = fstat(a, &a_stat);
182 if (ret) {
183 PERROR("Failed to fstat userspace probe location binary fd %d",
184 a);
185 goto end;
186 }
187
188 ret = fstat(b, &b_stat);
189 if (ret) {
190 PERROR("Failed to fstat userspace probe location binary fd %d",
191 b);
192 goto end;
193 }
194
195 is_equal = (a_stat.st_ino == b_stat.st_ino) &&
196 (a_stat.st_dev == b_stat.st_dev);
197
198 end:
199 return is_equal;
200 }
201
202 static bool lttng_userspace_probe_location_function_is_equal(
203 const struct lttng_userspace_probe_location *_a,
204 const struct lttng_userspace_probe_location *_b)
205 {
206 bool is_equal = false;
207 struct lttng_userspace_probe_location_function *a, *b;
208
209 a = container_of(_a, struct lttng_userspace_probe_location_function,
210 parent);
211 b = container_of(_b, struct lttng_userspace_probe_location_function,
212 parent);
213
214 if (a->instrumentation_type != b->instrumentation_type) {
215 goto end;
216 }
217
218 assert(a->function_name);
219 assert(b->function_name);
220 if (strcmp(a->function_name, b->function_name)) {
221 goto end;
222 }
223
224 assert(a->binary_path);
225 assert(b->binary_path);
226 if (strcmp(a->binary_path, b->binary_path)) {
227 goto end;
228 }
229
230 is_equal = fd_is_equal(a->binary_fd_handle ? fd_handle_get_fd(a->binary_fd_handle) : -1,
231 b->binary_fd_handle ? fd_handle_get_fd(b->binary_fd_handle) : -1);
232 end:
233 return is_equal;
234 }
235
236 static struct lttng_userspace_probe_location *
237 lttng_userspace_probe_location_function_create_no_check(const char *binary_path,
238 const char *function_name,
239 struct lttng_userspace_probe_location_lookup_method *lookup_method,
240 bool open_binary)
241 {
242 int binary_fd = -1;
243 struct fd_handle *binary_fd_handle = NULL;
244 char *function_name_copy = NULL, *binary_path_copy = NULL;
245 struct lttng_userspace_probe_location *ret = NULL;
246 struct lttng_userspace_probe_location_function *location;
247
248 if (open_binary) {
249 binary_fd = open(binary_path, O_RDONLY);
250 if (binary_fd < 0) {
251 PERROR("Error opening the binary");
252 goto error;
253 }
254
255 binary_fd_handle = fd_handle_create(binary_fd);
256 if (!binary_fd) {
257 goto error;
258 }
259
260 /* Ownership transferred to fd_handle. */
261 binary_fd = -1;
262 }
263
264 function_name_copy = lttng_strndup(function_name, LTTNG_SYMBOL_NAME_LEN);
265 if (!function_name_copy) {
266 PERROR("Error duplicating the function name");
267 goto error;
268 }
269
270 binary_path_copy = lttng_strndup(binary_path, LTTNG_PATH_MAX);
271 if (!binary_path_copy) {
272 PERROR("Error duplicating the function name");
273 goto error;
274 }
275
276 location = zmalloc(sizeof(*location));
277 if (!location) {
278 PERROR("Error allocating userspace probe location");
279 goto error;
280 }
281
282 location->function_name = function_name_copy;
283 location->binary_path = binary_path_copy;
284 location->binary_fd_handle = binary_fd_handle;
285 binary_fd_handle = NULL;
286 location->instrumentation_type =
287 LTTNG_USERSPACE_PROBE_LOCATION_FUNCTION_INSTRUMENTATION_TYPE_ENTRY;
288
289 ret = &location->parent;
290 ret->lookup_method = lookup_method;
291 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION;
292 ret->equal = lttng_userspace_probe_location_function_is_equal;
293 goto end;
294
295 error:
296 free(function_name_copy);
297 free(binary_path_copy);
298 if (binary_fd >= 0) {
299 if (close(binary_fd)) {
300 PERROR("Error closing binary fd in error path");
301 }
302 }
303 fd_handle_put(binary_fd_handle);
304 end:
305 return ret;
306 }
307
308 static bool lttng_userspace_probe_location_tracepoint_is_equal(
309 const struct lttng_userspace_probe_location *_a,
310 const struct lttng_userspace_probe_location *_b)
311 {
312 bool is_equal = false;
313 struct lttng_userspace_probe_location_tracepoint *a, *b;
314
315 a = container_of(_a, struct lttng_userspace_probe_location_tracepoint,
316 parent);
317 b = container_of(_b, struct lttng_userspace_probe_location_tracepoint,
318 parent);
319
320 assert(a->probe_name);
321 assert(b->probe_name);
322 if (strcmp(a->probe_name, b->probe_name)) {
323 goto end;
324 }
325
326 assert(a->provider_name);
327 assert(b->provider_name);
328 if (strcmp(a->provider_name, b->provider_name)) {
329 goto end;
330 }
331
332 assert(a->binary_path);
333 assert(b->binary_path);
334 if (strcmp(a->binary_path, b->binary_path)) {
335 goto end;
336 }
337
338 is_equal = fd_is_equal(a->binary_fd_handle ? fd_handle_get_fd(a->binary_fd_handle) : -1,
339 b->binary_fd_handle ? fd_handle_get_fd(b->binary_fd_handle) : -1);
340
341 end:
342 return is_equal;
343 }
344
345 static struct lttng_userspace_probe_location *
346 lttng_userspace_probe_location_tracepoint_create_no_check(const char *binary_path,
347 const char *provider_name, const char *probe_name,
348 struct lttng_userspace_probe_location_lookup_method *lookup_method,
349 bool open_binary)
350 {
351 int binary_fd = -1;
352 struct fd_handle *binary_fd_handle = NULL;
353 char *probe_name_copy = NULL;
354 char *provider_name_copy = NULL;
355 char *binary_path_copy = NULL;
356 struct lttng_userspace_probe_location *ret = NULL;
357 struct lttng_userspace_probe_location_tracepoint *location;
358
359 if (open_binary) {
360 binary_fd = open(binary_path, O_RDONLY);
361 if (binary_fd < 0) {
362 PERROR("open");
363 goto error;
364 }
365
366 binary_fd_handle = fd_handle_create(binary_fd);
367 if (!binary_fd) {
368 goto error;
369 }
370
371 /* Ownership transferred to fd_handle. */
372 binary_fd = -1;
373 }
374
375 probe_name_copy = lttng_strndup(probe_name, LTTNG_SYMBOL_NAME_LEN);
376 if (!probe_name_copy) {
377 PERROR("lttng_strndup");
378 goto error;
379 }
380
381 provider_name_copy = lttng_strndup(provider_name, LTTNG_SYMBOL_NAME_LEN);
382 if (!provider_name_copy) {
383 PERROR("lttng_strndup");
384 goto error;
385 }
386
387 binary_path_copy = lttng_strndup(binary_path, LTTNG_PATH_MAX);
388 if (!binary_path_copy) {
389 PERROR("lttng_strndup");
390 goto error;
391 }
392
393 location = zmalloc(sizeof(*location));
394 if (!location) {
395 PERROR("zmalloc");
396 goto error;
397 }
398
399 location->probe_name = probe_name_copy;
400 location->provider_name = provider_name_copy;
401 location->binary_path = binary_path_copy;
402 location->binary_fd_handle = binary_fd_handle;
403 binary_fd_handle = NULL;
404
405 ret = &location->parent;
406 ret->lookup_method = lookup_method;
407 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT;
408 ret->equal = lttng_userspace_probe_location_tracepoint_is_equal;
409 goto end;
410
411 error:
412 free(probe_name_copy);
413 free(provider_name_copy);
414 free(binary_path_copy);
415 if (binary_fd >= 0) {
416 if (close(binary_fd)) {
417 PERROR("Error closing binary fd in error path");
418 }
419 }
420 fd_handle_put(binary_fd_handle);
421 end:
422 return ret;
423 }
424
425 struct lttng_userspace_probe_location *
426 lttng_userspace_probe_location_function_create(const char *binary_path,
427 const char *function_name,
428 struct lttng_userspace_probe_location_lookup_method *lookup_method)
429 {
430 struct lttng_userspace_probe_location *ret = NULL;
431
432 if (!binary_path || !function_name) {
433 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
434 goto end;
435 }
436
437 switch (lttng_userspace_probe_location_lookup_method_get_type(
438 lookup_method)) {
439 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
440 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
441 break;
442 default:
443 /* Invalid probe location lookup method. */
444 goto end;
445 }
446
447 ret = lttng_userspace_probe_location_function_create_no_check(
448 binary_path, function_name, lookup_method, true);
449 end:
450 return ret;
451 }
452
453 struct lttng_userspace_probe_location *
454 lttng_userspace_probe_location_tracepoint_create(const char *binary_path,
455 const char *provider_name, const char *probe_name,
456 struct lttng_userspace_probe_location_lookup_method *lookup_method)
457 {
458 struct lttng_userspace_probe_location *ret = NULL;
459
460 if (!binary_path || !probe_name || !provider_name) {
461 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
462 goto end;
463 }
464
465 switch (lttng_userspace_probe_location_lookup_method_get_type(
466 lookup_method)) {
467 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
468 break;
469 default:
470 /* Invalid probe location lookup method. */
471 goto end;
472 }
473
474 ret = lttng_userspace_probe_location_tracepoint_create_no_check(
475 binary_path, provider_name, probe_name, lookup_method, true);
476 end:
477 return ret;
478 }
479
480 static struct lttng_userspace_probe_location_lookup_method *
481 lttng_userspace_probe_location_lookup_method_function_elf_copy(
482 const struct lttng_userspace_probe_location_lookup_method *lookup_method)
483 {
484 struct lttng_userspace_probe_location_lookup_method *parent = NULL;
485 struct lttng_userspace_probe_location_lookup_method_elf *elf_method;
486
487 assert(lookup_method);
488 assert(lookup_method->type ==
489 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF);
490
491 elf_method = zmalloc(sizeof(*elf_method));
492 if (!elf_method) {
493 PERROR("Error allocating ELF userspace probe lookup method");
494 goto error;
495 }
496
497 elf_method->parent.type = lookup_method->type;
498 parent = &elf_method->parent;
499
500 goto end;
501 error:
502 parent = NULL;
503 end:
504 return parent;
505 }
506
507 static struct lttng_userspace_probe_location_lookup_method *
508 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_copy(
509 struct lttng_userspace_probe_location_lookup_method *lookup_method)
510 {
511 struct lttng_userspace_probe_location_lookup_method *parent = NULL;
512 struct lttng_userspace_probe_location_lookup_method_sdt *sdt_method;
513
514 assert(lookup_method);
515 assert(lookup_method->type ==
516 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT);
517
518 sdt_method = zmalloc(sizeof(*sdt_method));
519 if (!sdt_method) {
520 PERROR("zmalloc");
521 goto error;
522 }
523
524 sdt_method->parent.type = lookup_method->type;
525 parent = &sdt_method->parent;
526
527 goto end;
528
529 error:
530 parent = NULL;
531 end:
532 return parent;
533 }
534
535 static struct lttng_userspace_probe_location *
536 lttng_userspace_probe_location_function_copy(
537 const struct lttng_userspace_probe_location *location)
538 {
539 enum lttng_userspace_probe_location_lookup_method_type lookup_type;
540 struct lttng_userspace_probe_location *new_location = NULL;
541 struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
542 const char *binary_path = NULL;
543 const char *function_name = NULL;
544 struct lttng_userspace_probe_location_function *function_location;
545
546 assert(location);
547 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
548 function_location = container_of(
549 location, typeof(*function_location), parent);
550
551 /* Get probe location fields */
552 binary_path = lttng_userspace_probe_location_function_get_binary_path(location);
553 if (!binary_path) {
554 ERR("Userspace probe binary path is NULL");
555 goto error;
556 }
557
558 function_name = lttng_userspace_probe_location_function_get_function_name(location);
559 if (!function_name) {
560 ERR("Userspace probe function name is NULL");
561 goto error;
562 }
563
564 /*
565 * Duplicate probe location method fields
566 */
567 lookup_type = lttng_userspace_probe_location_lookup_method_get_type(
568 location->lookup_method);
569 switch (lookup_type) {
570 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
571 lookup_method =
572 lttng_userspace_probe_location_lookup_method_function_elf_copy(
573 location->lookup_method);
574 if (!lookup_method) {
575 goto error;
576 }
577 break;
578 default:
579 /* Invalid probe location lookup method. */
580 goto error;
581 }
582
583 /* Create the probe_location */
584 new_location = lttng_userspace_probe_location_function_create_no_check(
585 binary_path, function_name, lookup_method, false);
586 if (!new_location) {
587 goto destroy_lookup_method;
588 }
589
590 /* Set the duplicated fd to the new probe_location */
591 if (lttng_userspace_probe_location_function_set_binary_fd_handle(new_location,
592 function_location->binary_fd_handle) < 0) {
593 goto destroy_probe_location;
594 }
595
596 goto end;
597
598 destroy_probe_location:
599 lttng_userspace_probe_location_destroy(new_location);
600 destroy_lookup_method:
601 lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
602 error:
603 new_location = NULL;
604 end:
605 return new_location;
606 }
607
608 static struct lttng_userspace_probe_location *
609 lttng_userspace_probe_location_tracepoint_copy(
610 const struct lttng_userspace_probe_location *location)
611 {
612 enum lttng_userspace_probe_location_lookup_method_type lookup_type;
613 struct lttng_userspace_probe_location *new_location = NULL;
614 struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
615 const char *binary_path = NULL;
616 const char *probe_name = NULL;
617 const char *provider_name = NULL;
618 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
619
620 assert(location);
621 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
622 tracepoint_location = container_of(
623 location, typeof(*tracepoint_location), parent);
624
625 /* Get probe location fields */
626 binary_path = lttng_userspace_probe_location_tracepoint_get_binary_path(location);
627 if (!binary_path) {
628 ERR("Userspace probe binary path is NULL");
629 goto error;
630 }
631
632 probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(location);
633 if (!probe_name) {
634 ERR("Userspace probe probe name is NULL");
635 goto error;
636 }
637
638 provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(location);
639 if (!provider_name) {
640 ERR("Userspace probe provider name is NULL");
641 goto error;
642 }
643
644 /*
645 * Duplicate probe location method fields
646 */
647 lookup_type = lttng_userspace_probe_location_lookup_method_get_type(
648 location->lookup_method);
649 switch (lookup_type) {
650 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
651 lookup_method =
652 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_copy(
653 location->lookup_method);
654 if (!lookup_method) {
655 goto error;
656 }
657 break;
658 default:
659 /* Invalid probe location lookup method. */
660 goto error;
661 }
662
663 /* Create the probe_location */
664 new_location = lttng_userspace_probe_location_tracepoint_create_no_check(
665 binary_path, provider_name, probe_name, lookup_method, false);
666 if (!new_location) {
667 goto destroy_lookup_method;
668 }
669
670 /* Set the duplicated fd to the new probe_location */
671 if (lttng_userspace_probe_location_tracepoint_set_binary_fd_handle(new_location,
672 tracepoint_location->binary_fd_handle) < 0) {
673 goto destroy_probe_location;
674 }
675
676 goto end;
677
678 destroy_probe_location:
679 lttng_userspace_probe_location_destroy(new_location);
680 destroy_lookup_method:
681 lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
682 error:
683 new_location = NULL;
684 end:
685 return new_location;
686 }
687
688 const char *lttng_userspace_probe_location_function_get_binary_path(
689 const struct lttng_userspace_probe_location *location)
690 {
691 const char *ret = NULL;
692 struct lttng_userspace_probe_location_function *function_location;
693
694 if (!location || lttng_userspace_probe_location_get_type(location) !=
695 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
696 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
697 goto end;
698 }
699
700 function_location = container_of(location,
701 struct lttng_userspace_probe_location_function,
702 parent);
703 ret = function_location->binary_path;
704 end:
705 return ret;
706 }
707
708 const char *lttng_userspace_probe_location_tracepoint_get_binary_path(
709 const struct lttng_userspace_probe_location *location)
710 {
711 const char *ret = NULL;
712 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
713
714 if (!location || lttng_userspace_probe_location_get_type(location) !=
715 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) {
716 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
717 goto end;
718 }
719
720 tracepoint_location = container_of(location,
721 struct lttng_userspace_probe_location_tracepoint,
722 parent);
723 ret = tracepoint_location->binary_path;
724 end:
725 return ret;
726 }
727
728 const char *lttng_userspace_probe_location_function_get_function_name(
729 const struct lttng_userspace_probe_location *location)
730 {
731 const char *ret = NULL;
732 struct lttng_userspace_probe_location_function *function_location;
733
734 if (!location || lttng_userspace_probe_location_get_type(location) !=
735 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
736 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
737 goto end;
738 }
739
740 function_location = container_of(location,
741 struct lttng_userspace_probe_location_function, parent);
742 ret = function_location->function_name;
743 end:
744 return ret;
745 }
746
747 const char *lttng_userspace_probe_location_tracepoint_get_probe_name(
748 const struct lttng_userspace_probe_location *location)
749 {
750 const char *ret = NULL;
751 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
752
753 if (!location || lttng_userspace_probe_location_get_type(location) !=
754 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) {
755 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
756 goto end;
757 }
758
759 tracepoint_location = container_of(location,
760 struct lttng_userspace_probe_location_tracepoint, parent);
761 ret = tracepoint_location->probe_name;
762 end:
763 return ret;
764 }
765
766 const char *lttng_userspace_probe_location_tracepoint_get_provider_name(
767 const struct lttng_userspace_probe_location *location)
768 {
769 const char *ret = NULL;
770 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
771
772 if (!location || lttng_userspace_probe_location_get_type(location) !=
773 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) {
774 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
775 goto end;
776 }
777
778 tracepoint_location = container_of(location,
779 struct lttng_userspace_probe_location_tracepoint, parent);
780 ret = tracepoint_location->provider_name;
781 end:
782 return ret;
783 }
784
785 int lttng_userspace_probe_location_function_get_binary_fd(
786 const struct lttng_userspace_probe_location *location)
787 {
788 int ret = -1;
789 struct lttng_userspace_probe_location_function *function_location;
790
791 if (!location || lttng_userspace_probe_location_get_type(location) !=
792 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
793 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
794 goto end;
795 }
796
797 function_location = container_of(location,
798 struct lttng_userspace_probe_location_function, parent);
799 ret = function_location->binary_fd_handle ?
800 fd_handle_get_fd(function_location->binary_fd_handle) : -1;
801 end:
802 return ret;
803 }
804
805 enum lttng_userspace_probe_location_function_instrumentation_type
806 lttng_userspace_probe_location_function_get_instrumentation_type(
807 const struct lttng_userspace_probe_location *location)
808 {
809 enum lttng_userspace_probe_location_function_instrumentation_type type;
810 struct lttng_userspace_probe_location_function *function_location;
811
812 if (!location || lttng_userspace_probe_location_get_type(location) !=
813 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
814 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
815 type = LTTNG_USERSPACE_PROBE_LOCATION_FUNCTION_INSTRUMENTATION_TYPE_UNKNOWN;
816 goto end;
817 }
818
819 function_location = container_of(location,
820 struct lttng_userspace_probe_location_function, parent);
821 type = function_location->instrumentation_type;
822 end:
823 return type;
824 }
825
826 enum lttng_userspace_probe_location_status
827 lttng_userspace_probe_location_function_set_instrumentation_type(
828 const struct lttng_userspace_probe_location *location,
829 enum lttng_userspace_probe_location_function_instrumentation_type instrumentation_type)
830 {
831 enum lttng_userspace_probe_location_status status =
832 LTTNG_USERSPACE_PROBE_LOCATION_STATUS_OK;
833 struct lttng_userspace_probe_location_function *function_location;
834
835 if (!location || lttng_userspace_probe_location_get_type(location) !=
836 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION ||
837 instrumentation_type !=
838 LTTNG_USERSPACE_PROBE_LOCATION_FUNCTION_INSTRUMENTATION_TYPE_ENTRY) {
839 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
840 status = LTTNG_USERSPACE_PROBE_LOCATION_STATUS_INVALID;
841 goto end;
842 }
843
844 function_location = container_of(location,
845 struct lttng_userspace_probe_location_function, parent);
846 function_location->instrumentation_type = instrumentation_type;
847 end:
848 return status;
849 }
850
851 int lttng_userspace_probe_location_tracepoint_get_binary_fd(
852 const struct lttng_userspace_probe_location *location)
853 {
854 int ret = -1;
855 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
856
857 if (!location || lttng_userspace_probe_location_get_type(location) !=
858 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) {
859 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
860 goto end;
861 }
862
863 tracepoint_location = container_of(location,
864 struct lttng_userspace_probe_location_tracepoint, parent);
865 ret = tracepoint_location->binary_fd_handle ?
866 fd_handle_get_fd(tracepoint_location->binary_fd_handle) : -1;
867 end:
868 return ret;
869 }
870
871 static struct lttng_userspace_probe_location_lookup_method *
872 lttng_userspace_probe_location_function_get_lookup_method(
873 const struct lttng_userspace_probe_location *location)
874 {
875 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
876
877 if (!location || lttng_userspace_probe_location_get_type(location) !=
878 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
879 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
880 goto end;
881 }
882
883 ret = location->lookup_method;
884 end:
885 return ret;
886 }
887
888 static struct lttng_userspace_probe_location_lookup_method *
889 lttng_userspace_probe_location_tracepoint_get_lookup_method(
890 const struct lttng_userspace_probe_location *location)
891 {
892 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
893
894 if (!location || lttng_userspace_probe_location_get_type(location) !=
895 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) {
896 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
897 goto end;
898 }
899
900 ret = location->lookup_method;
901 end:
902 return ret;
903 }
904
905 const struct lttng_userspace_probe_location_lookup_method *
906 lttng_userspace_probe_location_get_lookup_method(
907 const struct lttng_userspace_probe_location *location)
908 {
909 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
910
911 assert(location);
912 switch (location->type) {
913 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
914 ret = lttng_userspace_probe_location_function_get_lookup_method(
915 location);
916 break;
917 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
918 ret = lttng_userspace_probe_location_tracepoint_get_lookup_method(
919 location);
920 break;
921 default:
922 ERR("Unknowned lookup method.");
923 break;
924 }
925 return ret;
926 }
927
928 static
929 int lttng_userspace_probe_location_lookup_method_serialize(
930 struct lttng_userspace_probe_location_lookup_method *method,
931 struct lttng_payload *payload)
932 {
933 int ret;
934 struct lttng_userspace_probe_location_lookup_method_comm
935 lookup_method_comm;
936
937 lookup_method_comm.type = (int8_t) (method ? method->type :
938 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT);
939 if (payload) {
940 ret = lttng_dynamic_buffer_append(&payload->buffer, &lookup_method_comm,
941 sizeof(lookup_method_comm));
942 if (ret) {
943 goto end;
944 }
945 }
946 ret = sizeof(lookup_method_comm);
947 end:
948 return ret;
949 }
950
951 static
952 int lttng_userspace_probe_location_function_serialize(
953 const struct lttng_userspace_probe_location *location,
954 struct lttng_payload *payload)
955 {
956 int ret;
957 size_t function_name_len, binary_path_len;
958 struct lttng_userspace_probe_location_function *location_function;
959 struct lttng_userspace_probe_location_function_comm location_function_comm;
960
961 assert(location);
962 assert(lttng_userspace_probe_location_get_type(location) ==
963 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
964
965 location_function = container_of(location,
966 struct lttng_userspace_probe_location_function,
967 parent);
968 if (!location_function->function_name || !location_function->binary_path) {
969 ret = -LTTNG_ERR_INVALID;
970 goto end;
971 }
972
973 if (payload && !location_function->binary_fd_handle) {
974 ret = -LTTNG_ERR_INVALID;
975 goto end;
976 }
977
978 function_name_len = strlen(location_function->function_name);
979 if (function_name_len == 0) {
980 ret = -LTTNG_ERR_INVALID;
981 goto end;
982 }
983 binary_path_len = strlen(location_function->binary_path);
984 if (binary_path_len == 0) {
985 ret = -LTTNG_ERR_INVALID;
986 goto end;
987 }
988
989 location_function_comm.function_name_len = function_name_len + 1;
990 location_function_comm.binary_path_len = binary_path_len + 1;
991
992 if (payload) {
993 ret = lttng_dynamic_buffer_append(&payload->buffer,
994 &location_function_comm,
995 sizeof(location_function_comm));
996 if (ret) {
997 ret = -LTTNG_ERR_INVALID;
998 goto end;
999 }
1000 ret = lttng_dynamic_buffer_append(&payload->buffer,
1001 location_function->function_name,
1002 location_function_comm.function_name_len);
1003 if (ret) {
1004 ret = -LTTNG_ERR_INVALID;
1005 goto end;
1006 }
1007 ret = lttng_dynamic_buffer_append(&payload->buffer,
1008 location_function->binary_path,
1009 location_function_comm.binary_path_len);
1010 if (ret) {
1011 ret = -LTTNG_ERR_INVALID;
1012 goto end;
1013 }
1014 ret = lttng_payload_push_fd_handle(
1015 payload, location_function->binary_fd_handle);
1016 if (ret) {
1017 ret = -LTTNG_ERR_INVALID;
1018 goto end;
1019 }
1020 }
1021 ret = sizeof(location_function_comm) +
1022 location_function_comm.function_name_len +
1023 location_function_comm.binary_path_len;
1024 end:
1025 return ret;
1026 }
1027
1028 static
1029 int lttng_userspace_probe_location_tracepoint_serialize(
1030 const struct lttng_userspace_probe_location *location,
1031 struct lttng_payload *payload)
1032 {
1033 int ret;
1034 size_t probe_name_len, provider_name_len, binary_path_len;
1035 struct lttng_userspace_probe_location_tracepoint *location_tracepoint;
1036 struct lttng_userspace_probe_location_tracepoint_comm location_tracepoint_comm;
1037
1038 assert(location);
1039 assert(lttng_userspace_probe_location_get_type(location) ==
1040 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
1041
1042 location_tracepoint = container_of(location,
1043 struct lttng_userspace_probe_location_tracepoint,
1044 parent);
1045 if (!location_tracepoint->probe_name ||
1046 !location_tracepoint->provider_name ||
1047 !location_tracepoint->binary_path) {
1048 ret = -LTTNG_ERR_INVALID;
1049 goto end;
1050 }
1051
1052 if (payload && !location_tracepoint->binary_fd_handle) {
1053 ret = -LTTNG_ERR_INVALID;
1054 goto end;
1055 }
1056
1057 probe_name_len = strlen(location_tracepoint->probe_name);
1058 if (probe_name_len == 0) {
1059 ret = -LTTNG_ERR_INVALID;
1060 goto end;
1061 }
1062
1063 provider_name_len = strlen(location_tracepoint->provider_name);
1064 if (provider_name_len == 0) {
1065 ret = -LTTNG_ERR_INVALID;
1066 goto end;
1067 }
1068
1069 binary_path_len = strlen(location_tracepoint->binary_path);
1070 if (binary_path_len == 0) {
1071 ret = -LTTNG_ERR_INVALID;
1072 goto end;
1073 }
1074
1075 location_tracepoint_comm.probe_name_len = probe_name_len + 1;
1076 location_tracepoint_comm.provider_name_len = provider_name_len + 1;
1077 location_tracepoint_comm.binary_path_len = binary_path_len + 1;
1078
1079 if (payload) {
1080 ret = lttng_dynamic_buffer_append(&payload->buffer,
1081 &location_tracepoint_comm,
1082 sizeof(location_tracepoint_comm));
1083 if (ret) {
1084 ret = -LTTNG_ERR_INVALID;
1085 goto end;
1086 }
1087 ret = lttng_dynamic_buffer_append(&payload->buffer,
1088 location_tracepoint->probe_name,
1089 location_tracepoint_comm.probe_name_len);
1090 if (ret) {
1091 ret = -LTTNG_ERR_INVALID;
1092 goto end;
1093 }
1094 ret = lttng_dynamic_buffer_append(&payload->buffer,
1095 location_tracepoint->provider_name,
1096 location_tracepoint_comm.provider_name_len);
1097 if (ret) {
1098 ret = -LTTNG_ERR_INVALID;
1099 goto end;
1100 }
1101 ret = lttng_dynamic_buffer_append(&payload->buffer,
1102 location_tracepoint->binary_path,
1103 location_tracepoint_comm.binary_path_len);
1104 if (ret) {
1105 ret = -LTTNG_ERR_INVALID;
1106 goto end;
1107 }
1108 ret = lttng_payload_push_fd_handle(
1109 payload, location_tracepoint->binary_fd_handle);
1110 if (ret) {
1111 ret = -LTTNG_ERR_INVALID;
1112 goto end;
1113 }
1114 }
1115
1116 ret = sizeof(location_tracepoint_comm) +
1117 location_tracepoint_comm.probe_name_len +
1118 location_tracepoint_comm.provider_name_len +
1119 location_tracepoint_comm.binary_path_len;
1120 end:
1121 return ret;
1122 }
1123
1124 LTTNG_HIDDEN
1125 int lttng_userspace_probe_location_serialize(
1126 const struct lttng_userspace_probe_location *location,
1127 struct lttng_payload *payload)
1128 {
1129 int ret, buffer_use = 0;
1130 struct lttng_userspace_probe_location_comm location_generic_comm;
1131
1132 if (!location) {
1133 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
1134 ret = -LTTNG_ERR_INVALID;
1135 goto end;
1136 }
1137
1138 memset(&location_generic_comm, 0, sizeof(location_generic_comm));
1139
1140 location_generic_comm.type = (int8_t) location->type;
1141 if (payload) {
1142 ret = lttng_dynamic_buffer_append(&payload->buffer,
1143 &location_generic_comm,
1144 sizeof(location_generic_comm));
1145 if (ret) {
1146 goto end;
1147 }
1148 }
1149 buffer_use += sizeof(location_generic_comm);
1150
1151 switch (lttng_userspace_probe_location_get_type(location)) {
1152 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
1153 ret = lttng_userspace_probe_location_function_serialize(
1154 location, payload);
1155 break;
1156 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
1157 ret = lttng_userspace_probe_location_tracepoint_serialize(
1158 location, payload);
1159 break;
1160 default:
1161 ERR("Unsupported probe location type");
1162 ret = -LTTNG_ERR_INVALID;
1163 goto end;
1164 }
1165 if (ret < 0) {
1166 goto end;
1167 }
1168 buffer_use += ret;
1169
1170 ret = lttng_userspace_probe_location_lookup_method_serialize(
1171 location->lookup_method, payload);
1172 if (ret < 0) {
1173 goto end;
1174 }
1175 ret += buffer_use;
1176 end:
1177 return ret;
1178 }
1179
1180 static
1181 int lttng_userspace_probe_location_function_create_from_payload(
1182 struct lttng_payload_view *view,
1183 struct lttng_userspace_probe_location **location)
1184 {
1185 struct lttng_userspace_probe_location_function_comm *location_function_comm;
1186 const char *function_name_src, *binary_path_src;
1187 char *function_name = NULL, *binary_path = NULL;
1188 int ret = 0;
1189 size_t expected_size;
1190 struct fd_handle *binary_fd_handle = lttng_payload_view_pop_fd_handle(view);
1191
1192 assert(location);
1193
1194 if (view->buffer.size < sizeof(*location_function_comm)) {
1195 ret = -LTTNG_ERR_INVALID;
1196 goto end;
1197 }
1198
1199 location_function_comm =
1200 (typeof(location_function_comm)) view->buffer.data;
1201
1202 expected_size = sizeof(*location_function_comm) +
1203 location_function_comm->function_name_len +
1204 location_function_comm->binary_path_len;
1205
1206 if (view->buffer.size < expected_size) {
1207 ret = -LTTNG_ERR_INVALID;
1208 goto end;
1209 }
1210
1211 function_name_src = view->buffer.data + sizeof(*location_function_comm);
1212 binary_path_src = function_name_src +
1213 location_function_comm->function_name_len;
1214
1215 if (!lttng_buffer_view_contains_string(&view->buffer, function_name_src,
1216 location_function_comm->function_name_len)) {
1217 ret = -LTTNG_ERR_INVALID;
1218 goto end;
1219 }
1220
1221 if (!lttng_buffer_view_contains_string(&view->buffer, binary_path_src,
1222 location_function_comm->binary_path_len)) {
1223 ret = -LTTNG_ERR_INVALID;
1224 goto end;
1225 }
1226
1227 function_name = lttng_strndup(function_name_src, LTTNG_SYMBOL_NAME_LEN);
1228 if (!function_name) {
1229 PERROR("lttng_strndup");
1230 ret = -LTTNG_ERR_NOMEM;
1231 goto end;
1232 }
1233
1234 binary_path = lttng_strndup(binary_path_src, LTTNG_PATH_MAX);
1235 if (!binary_path) {
1236 PERROR("lttng_strndup");
1237 ret = -LTTNG_ERR_NOMEM;
1238 goto end;
1239 }
1240
1241 *location = lttng_userspace_probe_location_function_create_no_check(
1242 binary_path, function_name, NULL, false);
1243 if (!(*location)) {
1244 ret = -LTTNG_ERR_INVALID;
1245 goto end;
1246 }
1247
1248 ret = lttng_userspace_probe_location_function_set_binary_fd_handle(
1249 *location, binary_fd_handle);
1250 if (ret) {
1251 ret = -LTTNG_ERR_INVALID;
1252 goto end;
1253 }
1254
1255 ret = (int) expected_size;
1256 end:
1257 fd_handle_put(binary_fd_handle);
1258 free(function_name);
1259 free(binary_path);
1260 return ret;
1261 }
1262
1263 static
1264 int lttng_userspace_probe_location_tracepoint_create_from_payload(
1265 struct lttng_payload_view *view,
1266 struct lttng_userspace_probe_location **location)
1267 {
1268 struct lttng_userspace_probe_location_tracepoint_comm *location_tracepoint_comm;
1269 const char *probe_name_src, *provider_name_src, *binary_path_src;
1270 char *probe_name = NULL, *provider_name = NULL, *binary_path = NULL;
1271 int ret = 0;
1272 size_t expected_size;
1273 struct fd_handle *binary_fd_handle = lttng_payload_view_pop_fd_handle(view);
1274
1275 assert(location);
1276
1277 if (!binary_fd_handle) {
1278 ret = -LTTNG_ERR_INVALID;
1279 goto end;
1280 }
1281
1282 if (view->buffer.size < sizeof(*location_tracepoint_comm)) {
1283 ret = -LTTNG_ERR_INVALID;
1284 goto end;
1285 }
1286
1287 location_tracepoint_comm =
1288 (typeof(location_tracepoint_comm)) view->buffer.data;
1289
1290 expected_size = sizeof(*location_tracepoint_comm) +
1291 location_tracepoint_comm->probe_name_len +
1292 location_tracepoint_comm->provider_name_len +
1293 location_tracepoint_comm->binary_path_len;
1294
1295 if (view->buffer.size < expected_size) {
1296 ret = -LTTNG_ERR_INVALID;
1297 goto end;
1298 }
1299
1300 probe_name_src = view->buffer.data + sizeof(*location_tracepoint_comm);
1301 provider_name_src = probe_name_src +
1302 location_tracepoint_comm->probe_name_len;
1303 binary_path_src = provider_name_src +
1304 location_tracepoint_comm->provider_name_len;
1305
1306 if (!lttng_buffer_view_contains_string(&view->buffer, probe_name_src,
1307 location_tracepoint_comm->probe_name_len)) {
1308 ret = -LTTNG_ERR_INVALID;
1309 goto end;
1310 }
1311
1312 if (!lttng_buffer_view_contains_string(&view->buffer, provider_name_src,
1313 location_tracepoint_comm->provider_name_len)) {
1314 ret = -LTTNG_ERR_INVALID;
1315 goto end;
1316 }
1317
1318 if (!lttng_buffer_view_contains_string(&view->buffer, binary_path_src,
1319 location_tracepoint_comm->binary_path_len)) {
1320 ret = -LTTNG_ERR_INVALID;
1321 goto end;
1322 }
1323
1324 probe_name = lttng_strndup(probe_name_src, LTTNG_SYMBOL_NAME_LEN);
1325 if (!probe_name) {
1326 PERROR("lttng_strndup");
1327 goto end;
1328 }
1329 provider_name = lttng_strndup(provider_name_src, LTTNG_SYMBOL_NAME_LEN);
1330 if (!provider_name) {
1331 PERROR("lttng_strndup");
1332 goto end;
1333 }
1334
1335 binary_path = lttng_strndup(binary_path_src, LTTNG_SYMBOL_NAME_LEN);
1336 if (!binary_path) {
1337 PERROR("lttng_strndup");
1338 goto end;
1339 }
1340
1341 *location = lttng_userspace_probe_location_tracepoint_create_no_check(
1342 binary_path, provider_name, probe_name, NULL, false);
1343 if (!(*location)) {
1344 ret = -LTTNG_ERR_INVALID;
1345 goto end;
1346 }
1347
1348 ret = lttng_userspace_probe_location_tracepoint_set_binary_fd_handle(
1349 *location, binary_fd_handle);
1350 if (ret) {
1351 ret = -LTTNG_ERR_INVALID;
1352 goto end;
1353 }
1354
1355 ret = (int) expected_size;
1356 end:
1357 fd_handle_put(binary_fd_handle);
1358 free(probe_name);
1359 free(provider_name);
1360 free(binary_path);
1361 return ret;
1362 }
1363
1364 static
1365 int lttng_userspace_probe_location_lookup_method_create_from_payload(
1366 struct lttng_payload_view *view,
1367 struct lttng_userspace_probe_location_lookup_method **lookup_method)
1368 {
1369 int ret;
1370 struct lttng_userspace_probe_location_lookup_method_comm *lookup_comm;
1371 enum lttng_userspace_probe_location_lookup_method_type type;
1372
1373 assert(view);
1374 assert(lookup_method);
1375
1376 if (view->buffer.size < sizeof(*lookup_comm)) {
1377 ret = -LTTNG_ERR_INVALID;
1378 goto end;
1379 }
1380
1381 lookup_comm = (typeof(lookup_comm)) view->buffer.data;
1382 type = (enum lttng_userspace_probe_location_lookup_method_type)
1383 lookup_comm->type;
1384 switch (type) {
1385 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
1386 *lookup_method = NULL;
1387 break;
1388 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
1389 *lookup_method =
1390 lttng_userspace_probe_location_lookup_method_function_elf_create();
1391 if (!(*lookup_method)) {
1392 ret = -LTTNG_ERR_INVALID;
1393 goto end;
1394 }
1395 break;
1396 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
1397 *lookup_method =
1398 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
1399 if (!(*lookup_method)) {
1400 ret = -LTTNG_ERR_INVALID;
1401 goto end;
1402 }
1403 break;
1404 default:
1405 ret = -LTTNG_ERR_INVALID;
1406 goto end;
1407 }
1408
1409 ret = sizeof(*lookup_comm);
1410 end:
1411 return ret;
1412 }
1413
1414 LTTNG_HIDDEN
1415 int lttng_userspace_probe_location_create_from_payload(
1416 struct lttng_payload_view *view,
1417 struct lttng_userspace_probe_location **location)
1418 {
1419 struct lttng_userspace_probe_location_lookup_method *lookup_method;
1420 struct lttng_userspace_probe_location_comm *probe_location_comm;
1421 enum lttng_userspace_probe_location_type type;
1422 int consumed = 0;
1423 int ret;
1424
1425 assert(view);
1426 assert(location);
1427
1428 lookup_method = NULL;
1429
1430 if (view->buffer.size <= sizeof(*probe_location_comm)) {
1431 ret = -LTTNG_ERR_INVALID;
1432 goto end;
1433 }
1434
1435 probe_location_comm = (typeof(probe_location_comm)) view->buffer.data;
1436 type = (enum lttng_userspace_probe_location_type) probe_location_comm->type;
1437 consumed += sizeof(*probe_location_comm);
1438
1439 switch (type) {
1440 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
1441 {
1442 struct lttng_payload_view location_view =
1443 lttng_payload_view_from_view(
1444 view, consumed, -1);
1445
1446 ret = lttng_userspace_probe_location_function_create_from_payload(
1447 &location_view, location);
1448 if (ret < 0) {
1449 goto end;
1450 }
1451 break;
1452 }
1453 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
1454 {
1455 struct lttng_payload_view location_view =
1456 lttng_payload_view_from_view(view, consumed, -1);
1457
1458 ret = lttng_userspace_probe_location_tracepoint_create_from_payload(
1459 &location_view, location);
1460 if (ret < 0) {
1461 goto end;
1462 }
1463 break;
1464 }
1465 default:
1466 ret = -LTTNG_ERR_INVALID;
1467 goto end;
1468 }
1469
1470 consumed += ret;
1471 if (view->buffer.size <= consumed) {
1472 ret = -LTTNG_ERR_INVALID;
1473 goto end;
1474 }
1475
1476 {
1477 struct lttng_payload_view lookup_method_view =
1478 lttng_payload_view_from_view(
1479 view, consumed, -1);
1480
1481 ret = lttng_userspace_probe_location_lookup_method_create_from_payload(
1482 &lookup_method_view, &lookup_method);
1483 }
1484 if (ret < 0) {
1485 ret = -LTTNG_ERR_INVALID;
1486 goto end;
1487 }
1488
1489 assert(lookup_method);
1490 (*location)->lookup_method = lookup_method;
1491 lookup_method = NULL;
1492 ret += consumed;
1493 end:
1494 return ret;
1495 }
1496
1497 static
1498 int lttng_userspace_probe_location_function_set_binary_fd_handle(
1499 struct lttng_userspace_probe_location *location,
1500 struct fd_handle *binary_fd)
1501 {
1502 int ret = 0;
1503 struct lttng_userspace_probe_location_function *function_location;
1504
1505 assert(location);
1506 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
1507
1508 function_location = container_of(location,
1509 struct lttng_userspace_probe_location_function, parent);
1510 fd_handle_put(function_location->binary_fd_handle);
1511 fd_handle_get(binary_fd);
1512 function_location->binary_fd_handle = binary_fd;
1513 return ret;
1514 }
1515
1516 static
1517 int lttng_userspace_probe_location_tracepoint_set_binary_fd_handle(
1518 struct lttng_userspace_probe_location *location,
1519 struct fd_handle *binary_fd)
1520 {
1521 int ret = 0;
1522 struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
1523
1524 assert(location);
1525 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
1526
1527 tracepoint_location = container_of(location,
1528 struct lttng_userspace_probe_location_tracepoint, parent);
1529 fd_handle_put(tracepoint_location->binary_fd_handle);
1530 fd_handle_get(binary_fd);
1531 tracepoint_location->binary_fd_handle = binary_fd;
1532 return ret;
1533 }
1534
1535 static
1536 int lttng_userspace_probe_location_function_flatten(
1537 const struct lttng_userspace_probe_location *location,
1538 struct lttng_dynamic_buffer *buffer)
1539 {
1540 struct lttng_userspace_probe_location_lookup_method_elf flat_lookup_method;
1541 struct lttng_userspace_probe_location_function *probe_function;
1542 struct lttng_userspace_probe_location_function flat_probe;
1543 size_t function_name_len, binary_path_len;
1544 size_t padding_needed = 0;
1545 char *flat_probe_start;
1546 int storage_needed = 0;
1547 int ret;
1548
1549 assert(location);
1550
1551 if (location->lookup_method && location->lookup_method->type !=
1552 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF) {
1553 ret = -LTTNG_ERR_INVALID;
1554 goto end;
1555 }
1556
1557 probe_function = container_of(location,
1558 struct lttng_userspace_probe_location_function,
1559 parent);
1560 assert(probe_function->function_name);
1561 assert(probe_function->binary_path);
1562
1563 storage_needed +=
1564 sizeof(struct lttng_userspace_probe_location_function);
1565 function_name_len = strlen(probe_function->function_name) + 1;
1566 binary_path_len = strlen(probe_function->binary_path) + 1;
1567 storage_needed += function_name_len + binary_path_len;
1568
1569 /*
1570 * The lookup method is aligned to 64-bit within the buffer.
1571 * This is needed even if there is no lookup method since
1572 * the next structure in the buffer probably needs to be
1573 * aligned too (depending on the arch).
1574 */
1575 padding_needed = ALIGN_TO(storage_needed, sizeof(uint64_t)) - storage_needed;
1576 storage_needed += padding_needed;
1577
1578 if (location->lookup_method) {
1579 /* NOTE: elf look-up method is assumed here. */
1580 storage_needed += sizeof(struct lttng_userspace_probe_location_lookup_method_elf);
1581 }
1582
1583 if (!buffer) {
1584 ret = storage_needed;
1585 goto end;
1586 }
1587
1588 if (lttng_dynamic_buffer_get_capacity_left(buffer) < storage_needed) {
1589 ret = lttng_dynamic_buffer_set_capacity(buffer,
1590 buffer->size + storage_needed);
1591 if (ret) {
1592 goto end;
1593 }
1594 }
1595
1596 memset(&flat_probe, 0, sizeof(flat_probe));
1597
1598 flat_probe_start = buffer->data + buffer->size;
1599 flat_probe.parent.type = location->type;
1600 /*
1601 * The lookup method, if present, is the last element in the flat
1602 * representation of the probe.
1603 */
1604 if (location->lookup_method) {
1605 flat_probe.parent.lookup_method =
1606 (struct lttng_userspace_probe_location_lookup_method *)
1607 (flat_probe_start + sizeof(flat_probe) +
1608 function_name_len + binary_path_len + padding_needed);
1609 } else {
1610 flat_probe.parent.lookup_method = NULL;
1611 }
1612
1613 flat_probe.function_name = flat_probe_start + sizeof(flat_probe);
1614 flat_probe.binary_path = flat_probe.function_name + function_name_len;
1615 flat_probe.binary_fd_handle = NULL;
1616 ret = lttng_dynamic_buffer_append(buffer, &flat_probe,
1617 sizeof(flat_probe));
1618 if (ret) {
1619 goto end;
1620 }
1621
1622 ret = lttng_dynamic_buffer_append(buffer,
1623 probe_function->function_name, function_name_len);
1624 if (ret) {
1625 goto end;
1626 }
1627 ret = lttng_dynamic_buffer_append(buffer,
1628 probe_function->binary_path, binary_path_len);
1629 if (ret) {
1630 goto end;
1631 }
1632
1633 /* Insert padding before the lookup method. */
1634 ret = lttng_dynamic_buffer_set_size(buffer,
1635 buffer->size + padding_needed);
1636 if (ret) {
1637 goto end;
1638 }
1639
1640 if (!location->lookup_method) {
1641 /* Not an error, the default method is used. */
1642 ret = storage_needed;
1643 goto end;
1644 }
1645
1646 memset(&flat_lookup_method, 0, sizeof(flat_lookup_method));
1647 flat_lookup_method.parent.type =
1648 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF;
1649 ret = lttng_dynamic_buffer_append(buffer,
1650 &flat_lookup_method, sizeof(flat_lookup_method));
1651 if (ret) {
1652 goto end;
1653 }
1654 ret = storage_needed;
1655 end:
1656 return ret;
1657 }
1658
1659 static
1660 int lttng_userspace_probe_location_tracepoint_flatten(
1661 const struct lttng_userspace_probe_location *location,
1662 struct lttng_dynamic_buffer *buffer)
1663 {
1664 struct lttng_userspace_probe_location_lookup_method_sdt flat_lookup_method;
1665 struct lttng_userspace_probe_location_tracepoint *probe_tracepoint;
1666 struct lttng_userspace_probe_location_tracepoint flat_probe;
1667 size_t probe_name_len, provider_name_len, binary_path_len;
1668 size_t padding_needed = 0;
1669 int storage_needed = 0;
1670 char *flat_probe_start;
1671 int ret = 0;
1672
1673 assert(location);
1674
1675 /* Only SDT tracepoints are supported at the moment */
1676 if (location->lookup_method && location->lookup_method->type !=
1677 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT) {
1678 ret = -LTTNG_ERR_INVALID;
1679 goto end;
1680 }
1681 probe_tracepoint = container_of(location,
1682 struct lttng_userspace_probe_location_tracepoint,
1683 parent);
1684 assert(probe_tracepoint->probe_name);
1685 assert(probe_tracepoint->provider_name);
1686 assert(probe_tracepoint->binary_path);
1687
1688 /* Compute the storage space needed to flatten the probe location */
1689 storage_needed += sizeof(struct lttng_userspace_probe_location_tracepoint);
1690
1691 probe_name_len = strlen(probe_tracepoint->probe_name) + 1;
1692 provider_name_len = strlen(probe_tracepoint->provider_name) + 1;
1693 binary_path_len = strlen(probe_tracepoint->binary_path) + 1;
1694
1695 storage_needed += probe_name_len + provider_name_len + binary_path_len;
1696
1697 /*
1698 * The lookup method is aligned to 64-bit within the buffer.
1699 * This is needed even if there is no lookup method since
1700 * the next structure in the buffer probably needs to be
1701 * aligned too (depending on the arch).
1702 */
1703 padding_needed = ALIGN_TO(storage_needed, sizeof(uint64_t)) - storage_needed;
1704 storage_needed += padding_needed;
1705
1706 if (location->lookup_method) {
1707 /* NOTE: elf look-up method is assumed here. */
1708 storage_needed +=
1709 sizeof(struct lttng_userspace_probe_location_lookup_method_elf);
1710 }
1711
1712 /*
1713 * If the caller set buffer to NULL, return the size of the needed buffer.
1714 */
1715 if (!buffer) {
1716 ret = storage_needed;
1717 goto end;
1718 }
1719
1720 if (lttng_dynamic_buffer_get_capacity_left(buffer) < storage_needed) {
1721 ret = lttng_dynamic_buffer_set_capacity(buffer,
1722 buffer->size + storage_needed);
1723 if (ret) {
1724 goto end;
1725 }
1726 }
1727
1728 memset(&flat_probe, 0, sizeof(flat_probe));
1729
1730 flat_probe_start = buffer->data + buffer->size;
1731 flat_probe.parent.type = location->type;
1732
1733 /*
1734 * The lookup method, if present, is the last element in the flat
1735 * representation of the probe.
1736 */
1737 if (location->lookup_method) {
1738 flat_probe.parent.lookup_method =
1739 (struct lttng_userspace_probe_location_lookup_method *)
1740 (flat_probe_start + sizeof(flat_probe) +
1741 probe_name_len + provider_name_len +
1742 binary_path_len + padding_needed);
1743 } else {
1744 flat_probe.parent.lookup_method = NULL;
1745 }
1746
1747 flat_probe.probe_name = flat_probe_start + sizeof(flat_probe);
1748 flat_probe.provider_name = flat_probe.probe_name + probe_name_len;
1749 flat_probe.binary_path = flat_probe.provider_name + provider_name_len;
1750 flat_probe.binary_fd_handle = NULL;
1751 ret = lttng_dynamic_buffer_append(buffer, &flat_probe, sizeof(flat_probe));
1752 if (ret) {
1753 goto end;
1754 }
1755
1756 /* Append all the fields to the buffer */
1757 ret = lttng_dynamic_buffer_append(buffer,
1758 probe_tracepoint->probe_name, probe_name_len);
1759 if (ret) {
1760 goto end;
1761 }
1762 ret = lttng_dynamic_buffer_append(buffer,
1763 probe_tracepoint->provider_name, provider_name_len);
1764 if (ret) {
1765 goto end;
1766 }
1767 ret = lttng_dynamic_buffer_append(buffer,
1768 probe_tracepoint->binary_path, binary_path_len);
1769 if (ret) {
1770 goto end;
1771 }
1772
1773 /* Insert padding before the lookup method. */
1774 ret = lttng_dynamic_buffer_set_size(buffer, buffer->size + padding_needed);
1775 if (ret) {
1776 goto end;
1777 }
1778
1779 if (!location->lookup_method) {
1780 /* Not an error, the default method is used. */
1781 ret = storage_needed;
1782 goto end;
1783 }
1784
1785 memset(&flat_lookup_method, 0, sizeof(flat_lookup_method));
1786
1787 flat_lookup_method.parent.type =
1788 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT;
1789 ret = lttng_dynamic_buffer_append(buffer,
1790 &flat_lookup_method, sizeof(flat_lookup_method));
1791 if (ret) {
1792 goto end;
1793 }
1794 ret = storage_needed;
1795 end:
1796 return ret;
1797 }
1798
1799 LTTNG_HIDDEN
1800 int lttng_userspace_probe_location_flatten(
1801 const struct lttng_userspace_probe_location *location,
1802 struct lttng_dynamic_buffer *buffer)
1803 {
1804 int ret;
1805 if (!location) {
1806 ret = -LTTNG_ERR_INVALID;
1807 goto end;
1808 }
1809
1810 /* Only types currently supported. */
1811 switch (location->type) {
1812 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
1813 ret = lttng_userspace_probe_location_function_flatten(location, buffer);
1814 break;
1815 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
1816 ret = lttng_userspace_probe_location_tracepoint_flatten(location, buffer);
1817 break;
1818 default:
1819 ret = -LTTNG_ERR_INVALID;
1820 goto end;
1821 }
1822
1823 end:
1824 return ret;
1825 }
1826
1827 LTTNG_HIDDEN
1828 struct lttng_userspace_probe_location *lttng_userspace_probe_location_copy(
1829 const struct lttng_userspace_probe_location *location)
1830 {
1831 struct lttng_userspace_probe_location *new_location = NULL;
1832 enum lttng_userspace_probe_location_type type;
1833
1834 if (!location) {
1835 goto err;
1836 }
1837
1838 type = lttng_userspace_probe_location_get_type(location);
1839 switch (type) {
1840 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
1841 new_location =
1842 lttng_userspace_probe_location_function_copy(location);
1843 if (!new_location) {
1844 goto err;
1845 }
1846 break;
1847 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
1848 new_location =
1849 lttng_userspace_probe_location_tracepoint_copy(location);
1850 if (!new_location) {
1851 goto err;
1852 }
1853 break;
1854 default:
1855 new_location = NULL;
1856 goto err;
1857 }
1858 err:
1859 return new_location;
1860 }
1861
1862 LTTNG_HIDDEN
1863 bool lttng_userspace_probe_location_lookup_method_is_equal(
1864 const struct lttng_userspace_probe_location_lookup_method *a,
1865 const struct lttng_userspace_probe_location_lookup_method *b)
1866 {
1867 bool is_equal = false;
1868
1869 if (!a || !b) {
1870 goto end;
1871 }
1872
1873 if (a == b) {
1874 is_equal = true;
1875 goto end;
1876 }
1877
1878 if (a->type != b->type) {
1879 goto end;
1880 }
1881
1882 is_equal = true;
1883 end:
1884 return is_equal;
1885 }
1886
1887 LTTNG_HIDDEN
1888 bool lttng_userspace_probe_location_is_equal(
1889 const struct lttng_userspace_probe_location *a,
1890 const struct lttng_userspace_probe_location *b)
1891 {
1892 bool is_equal = false;
1893
1894 if (!a || !b) {
1895 goto end;
1896 }
1897
1898 if (a == b) {
1899 is_equal = true;
1900 goto end;
1901 }
1902
1903 if (!lttng_userspace_probe_location_lookup_method_is_equal(
1904 a->lookup_method, b->lookup_method)) {
1905 goto end;
1906 }
1907
1908 if (a->type != b->type) {
1909 goto end;
1910 }
1911
1912 is_equal = a->equal ? a->equal(a, b) : true;
1913 end:
1914 return is_equal;
1915 }
This page took 0.118043 seconds and 4 git commands to generate.