Add lttng_userspace_probe_location copy constructor
[lttng-tools.git] / src / common / userspace-probe.c
1 /*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include <assert.h>
19 #include <common/error.h>
20 #include <common/macros.h>
21 #include <common/compat/string.h>
22 #include <fcntl.h>
23 #include <lttng/constant.h>
24 #include <lttng/userspace-probe-internal.h>
25
26 enum lttng_userspace_probe_location_lookup_method_type
27 lttng_userspace_probe_location_lookup_method_get_type(
28 const struct lttng_userspace_probe_location_lookup_method *lookup_method)
29 {
30 return lookup_method ? lookup_method->type :
31 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_UNKNOWN;
32 }
33
34 void lttng_userspace_probe_location_lookup_method_destroy(
35 struct lttng_userspace_probe_location_lookup_method *lookup_method)
36 {
37 if (!lookup_method){
38 return;
39 }
40
41 switch (lookup_method->type) {
42 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
43 {
44 struct lttng_userspace_probe_location_lookup_method_elf *elf_method =
45 container_of(lookup_method,
46 struct lttng_userspace_probe_location_lookup_method_elf, parent);
47 free(elf_method);
48 break;
49 }
50 default:
51 break;
52 }
53 }
54
55 struct lttng_userspace_probe_location_lookup_method *
56 lttng_userspace_probe_location_lookup_method_function_elf_create(void)
57 {
58 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
59 struct lttng_userspace_probe_location_lookup_method_elf *elf_method;
60
61 elf_method = zmalloc(sizeof(*elf_method));
62 if (!elf_method) {
63 PERROR("zmalloc");
64 goto end;
65 }
66
67 ret = &elf_method->parent;
68 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF;
69 end:
70 return ret;
71 }
72
73 enum lttng_userspace_probe_location_type lttng_userspace_probe_location_get_type(
74 const struct lttng_userspace_probe_location *location)
75 {
76 return location ? location->type :
77 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_UNKNOWN;
78 }
79
80 static
81 void lttng_userspace_probe_location_function_destroy(
82 struct lttng_userspace_probe_location *location)
83 {
84 struct lttng_userspace_probe_location_function *location_function = NULL;
85
86 assert(location);
87
88 location_function = container_of(location,
89 struct lttng_userspace_probe_location_function, parent);
90
91 assert(location_function);
92
93 free(location_function->function_name);
94 free(location_function->binary_path);
95 if (location_function->binary_fd >= 0) {
96 if (close(location_function->binary_fd)) {
97 PERROR("close");
98 }
99 }
100 free(location);
101 }
102
103 void lttng_userspace_probe_location_destroy(
104 struct lttng_userspace_probe_location *location)
105 {
106 if (!location) {
107 return;
108 }
109
110 lttng_userspace_probe_location_lookup_method_destroy(
111 location->lookup_method);
112
113 switch (location->type) {
114 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
115 lttng_userspace_probe_location_function_destroy(location);
116 break;
117 default:
118 free(location);
119 }
120 }
121
122 static struct lttng_userspace_probe_location *
123 lttng_userspace_probe_location_function_create_no_check(const char *binary_path,
124 const char *function_name,
125 struct lttng_userspace_probe_location_lookup_method *lookup_method,
126 bool open_binary)
127 {
128 int binary_fd = -1;
129 char *function_name_copy = NULL, *binary_path_copy = NULL;
130 struct lttng_userspace_probe_location *ret = NULL;
131 struct lttng_userspace_probe_location_function *location;
132
133 if (open_binary) {
134 binary_fd = open(binary_path, O_RDONLY);
135 if (binary_fd < 0) {
136 PERROR("Error opening the binary");
137 goto error;
138 }
139 } else {
140 binary_fd = -1;
141 }
142
143 function_name_copy = lttng_strndup(function_name, LTTNG_SYMBOL_NAME_LEN);
144 if (!function_name_copy) {
145 PERROR("Error duplicating the function name");
146 goto error;
147 }
148
149 binary_path_copy = lttng_strndup(binary_path, LTTNG_PATH_MAX);
150 if (!binary_path_copy) {
151 PERROR("Error duplicating the function name");
152 goto error;
153 }
154
155 location = zmalloc(sizeof(*location));
156 if (!location) {
157 PERROR("Error allocating userspace probe location");
158 goto error;
159 }
160
161 location->function_name = function_name_copy;
162 location->binary_path = binary_path_copy;
163 location->binary_fd = binary_fd;
164
165 ret = &location->parent;
166 ret->lookup_method = lookup_method;
167 ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION;
168 goto end;
169
170 error:
171 free(function_name_copy);
172 free(binary_path_copy);
173 if (binary_fd >= 0) {
174 if (close(binary_fd)) {
175 PERROR("Error closing binary fd in error path");
176 }
177 }
178 end:
179 return ret;
180 }
181
182 struct lttng_userspace_probe_location *
183 lttng_userspace_probe_location_function_create(const char *binary_path,
184 const char *function_name,
185 struct lttng_userspace_probe_location_lookup_method *lookup_method)
186 {
187 struct lttng_userspace_probe_location *ret = NULL;
188
189 if (!binary_path || !function_name) {
190 ERR("Invalid argument(s)");
191 goto end;
192 }
193
194 switch (lttng_userspace_probe_location_lookup_method_get_type(
195 lookup_method)) {
196 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
197 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
198 break;
199 default:
200 /* Invalid probe location lookup method. */
201 goto end;
202 }
203
204 ret = lttng_userspace_probe_location_function_create_no_check(
205 binary_path, function_name, lookup_method, true);
206 end:
207 return ret;
208 }
209
210 static struct lttng_userspace_probe_location_lookup_method *
211 lttng_userspace_probe_location_lookup_method_function_elf_copy(
212 const struct lttng_userspace_probe_location_lookup_method *lookup_method)
213 {
214 struct lttng_userspace_probe_location_lookup_method *parent = NULL;
215 struct lttng_userspace_probe_location_lookup_method_elf *elf_method;
216
217 assert(lookup_method);
218 assert(lookup_method->type ==
219 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF);
220
221 elf_method = zmalloc(sizeof(*elf_method));
222 if (!elf_method) {
223 PERROR("Error allocating ELF userspace probe lookup method");
224 goto error;
225 }
226
227 elf_method->parent.type = lookup_method->type;
228 parent = &elf_method->parent;
229
230 goto end;
231 error:
232 parent = NULL;
233 end:
234 return parent;
235 }
236
237 static struct lttng_userspace_probe_location *
238 lttng_userspace_probe_location_function_copy(
239 const struct lttng_userspace_probe_location *location)
240 {
241 enum lttng_userspace_probe_location_lookup_method_type lookup_type;
242 struct lttng_userspace_probe_location *new_location = NULL;
243 struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
244 char *binary_path = NULL;
245 char *function_name = NULL;
246 int fd;
247
248 assert(location);
249 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
250
251 /* Duplicate probe location fields */
252 binary_path =
253 lttng_strndup(lttng_userspace_probe_location_function_get_binary_path(location),
254 LTTNG_PATH_MAX);
255 if (!binary_path) {
256 goto error;
257 }
258
259 function_name =
260 lttng_strndup(lttng_userspace_probe_location_function_get_function_name(location),
261 LTTNG_SYMBOL_NAME_LEN);
262 if (!function_name) {
263 PERROR("Error duplicating function name string");
264 goto error;
265 }
266
267 /* Duplicate the binary fd */
268 fd = dup(lttng_userspace_probe_location_function_get_binary_fd(location));
269 if (fd == -1) {
270 PERROR("Error duplicating file descriptor to binary");
271 goto error;
272 }
273
274 /*
275 * Duplicate probe location method fields
276 */
277 lookup_type = lttng_userspace_probe_location_lookup_method_get_type(
278 location->lookup_method);
279 switch (lookup_type) {
280 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
281 lookup_method =
282 lttng_userspace_probe_location_lookup_method_function_elf_copy(
283 location->lookup_method);
284 if (!lookup_method) {
285 goto close_fd;
286 }
287 break;
288 default:
289 /* Invalid probe location lookup method. */
290 goto close_fd;
291 }
292
293 /* Create the probe_location */
294 new_location = lttng_userspace_probe_location_function_create_no_check(
295 binary_path, function_name, lookup_method, true);
296 if (!new_location) {
297 goto destroy_lookup_method;
298 }
299
300 /* Set the duplicated fd to the new probe_location */
301 if (lttng_userspace_probe_location_function_set_binary_fd(new_location, fd) < 0) {
302 goto destroy_probe_location;
303 }
304
305 goto end;
306
307 destroy_probe_location:
308 lttng_userspace_probe_location_destroy(new_location);
309 destroy_lookup_method:
310 lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
311 close_fd:
312 if (close(fd) < 0) {
313 PERROR("Error closing duplicated file descriptor in error path");
314 }
315 error:
316 free(function_name);
317 free(binary_path);
318 new_location = NULL;
319 end:
320 return new_location;
321 }
322
323 const char *lttng_userspace_probe_location_function_get_binary_path(
324 const struct lttng_userspace_probe_location *location)
325 {
326 const char *ret = NULL;
327 struct lttng_userspace_probe_location_function *function_location;
328
329 if (!location || lttng_userspace_probe_location_get_type(location) !=
330 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
331 ERR("Invalid argument(s)");
332 goto end;
333 }
334
335 function_location = container_of(location,
336 struct lttng_userspace_probe_location_function,
337 parent);
338 ret = function_location->binary_path;
339 end:
340 return ret;
341 }
342
343 const char *lttng_userspace_probe_location_function_get_function_name(
344 const struct lttng_userspace_probe_location *location)
345 {
346 const char *ret = NULL;
347 struct lttng_userspace_probe_location_function *function_location;
348
349 if (!location || lttng_userspace_probe_location_get_type(location) !=
350 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
351 ERR("Invalid argument(s)");
352 goto end;
353 }
354
355 function_location = container_of(location,
356 struct lttng_userspace_probe_location_function, parent);
357 ret = function_location->function_name;
358 end:
359 return ret;
360 }
361
362 int lttng_userspace_probe_location_function_get_binary_fd(
363 const struct lttng_userspace_probe_location *location)
364 {
365 int ret = -1;
366 struct lttng_userspace_probe_location_function *function_location;
367
368 if (!location || lttng_userspace_probe_location_get_type(location) !=
369 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
370 ERR("Invalid argument(s)");
371 goto end;
372 }
373
374 function_location = container_of(location,
375 struct lttng_userspace_probe_location_function, parent);
376 ret = function_location->binary_fd;
377 end:
378 return ret;
379 }
380
381 static struct lttng_userspace_probe_location_lookup_method *
382 lttng_userspace_probe_location_function_get_lookup_method(
383 const struct lttng_userspace_probe_location *location)
384 {
385 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
386
387 if (!location || lttng_userspace_probe_location_get_type(location) !=
388 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION) {
389 ERR("Invalid argument(s)");
390 goto end;
391 }
392
393 ret = location->lookup_method;
394 end:
395 return ret;
396 }
397
398 struct lttng_userspace_probe_location_lookup_method *
399 lttng_userspace_probe_location_get_lookup_method(
400 const struct lttng_userspace_probe_location *location)
401 {
402 struct lttng_userspace_probe_location_lookup_method *ret = NULL;
403
404 assert(location);
405 switch (location->type) {
406 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
407 ret = lttng_userspace_probe_location_function_get_lookup_method(
408 location);
409 break;
410 default:
411 ERR("Unknowned lookup method.");
412 break;
413 }
414 return ret;
415 }
416
417 static
418 int lttng_userspace_probe_location_lookup_method_serialize(
419 struct lttng_userspace_probe_location_lookup_method *method,
420 struct lttng_dynamic_buffer *buffer)
421 {
422 int ret;
423 struct lttng_userspace_probe_location_lookup_method_comm
424 lookup_method_comm;
425
426 lookup_method_comm.type = (int8_t) (method ? method->type :
427 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT);
428 if (buffer) {
429 ret = lttng_dynamic_buffer_append(buffer, &lookup_method_comm,
430 sizeof(lookup_method_comm));
431 if (ret) {
432 goto end;
433 }
434 }
435 ret = sizeof(lookup_method_comm);
436 end:
437 return ret;
438 }
439
440 static
441 int lttng_userspace_probe_location_function_serialize(
442 const struct lttng_userspace_probe_location *location,
443 struct lttng_dynamic_buffer *buffer,
444 int *binary_fd)
445 {
446 int ret;
447 size_t function_name_len, binary_path_len;
448 struct lttng_userspace_probe_location_function *location_function;
449 struct lttng_userspace_probe_location_function_comm location_function_comm;
450
451 assert(location);
452 assert(lttng_userspace_probe_location_get_type(location) ==
453 LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
454
455 location_function = container_of(location,
456 struct lttng_userspace_probe_location_function,
457 parent);
458 if (!location_function->function_name || !location_function->binary_path) {
459 ret = -LTTNG_ERR_INVALID;
460 goto end;
461 }
462
463 if (binary_fd && location_function->binary_fd < 0) {
464 ret = -LTTNG_ERR_INVALID;
465 goto end;
466 }
467
468 if (binary_fd) {
469 *binary_fd = location_function->binary_fd;
470 }
471
472 function_name_len = strlen(location_function->function_name);
473 if (function_name_len == 0) {
474 ret = -LTTNG_ERR_INVALID;
475 goto end;
476 }
477 binary_path_len = strlen(location_function->binary_path);
478 if (binary_path_len == 0) {
479 ret = -LTTNG_ERR_INVALID;
480 goto end;
481 }
482
483 location_function_comm.function_name_len = function_name_len + 1;
484 location_function_comm.binary_path_len = binary_path_len + 1;
485
486 if (buffer) {
487 ret = lttng_dynamic_buffer_append(buffer,
488 &location_function_comm,
489 sizeof(location_function_comm));
490 if (ret) {
491 ret = -LTTNG_ERR_INVALID;
492 goto end;
493 }
494 ret = lttng_dynamic_buffer_append(buffer,
495 location_function->function_name,
496 location_function_comm.function_name_len);
497 if (ret) {
498 ret = -LTTNG_ERR_INVALID;
499 goto end;
500 }
501 ret = lttng_dynamic_buffer_append(buffer,
502 location_function->binary_path,
503 location_function_comm.binary_path_len);
504 if (ret) {
505 ret = -LTTNG_ERR_INVALID;
506 goto end;
507 }
508 }
509 ret = sizeof(location_function_comm) +
510 location_function_comm.function_name_len +
511 location_function_comm.binary_path_len;
512 end:
513 return ret;
514 }
515
516 LTTNG_HIDDEN
517 int lttng_userspace_probe_location_serialize(
518 const struct lttng_userspace_probe_location *location,
519 struct lttng_dynamic_buffer *buffer,
520 int *binary_fd)
521 {
522 int ret, buffer_use = 0;
523 struct lttng_userspace_probe_location_comm location_generic_comm;
524
525 if (!location) {
526 ERR("Invalid argument(s)");
527 ret = -LTTNG_ERR_INVALID;
528 goto end;
529 }
530
531 memset(&location_generic_comm, 0, sizeof(location_generic_comm));
532
533 location_generic_comm.type = (int8_t) location->type;
534 if (buffer) {
535 ret = lttng_dynamic_buffer_append(buffer, &location_generic_comm,
536 sizeof(location_generic_comm));
537 if (ret) {
538 goto end;
539 }
540 }
541 buffer_use += sizeof(location_generic_comm);
542
543 switch (lttng_userspace_probe_location_get_type(location)) {
544 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
545 ret = lttng_userspace_probe_location_function_serialize(
546 location, buffer, binary_fd);
547 break;
548 default:
549 ERR("Unsupported probe location type");
550 ret = -LTTNG_ERR_INVALID;
551 goto end;
552 }
553 if (ret < 0) {
554 goto end;
555 }
556 buffer_use += ret;
557
558 ret = lttng_userspace_probe_location_lookup_method_serialize(
559 location->lookup_method, buffer);
560 if (ret < 0) {
561 goto end;
562 }
563 ret += buffer_use;
564 end:
565 return ret;
566 }
567
568 static
569 int lttng_userspace_probe_location_function_create_from_buffer(
570 const struct lttng_buffer_view *buffer,
571 struct lttng_userspace_probe_location **location)
572 {
573 struct lttng_userspace_probe_location_function_comm *location_function_comm;
574 const char *function_name_src, *binary_path_src;
575 char *function_name = NULL, *binary_path = NULL;
576 int ret = 0;
577
578 assert(buffer);
579 assert(buffer->data);
580 assert(location);
581
582 location_function_comm =
583 (struct lttng_userspace_probe_location_function_comm *) buffer->data;
584
585 const size_t expected_size = sizeof(*location_function_comm) +
586 location_function_comm->function_name_len +
587 location_function_comm->binary_path_len;
588
589 if (buffer->size < expected_size) {
590 ret = -LTTNG_ERR_INVALID;
591 goto end;
592 }
593
594 function_name_src = buffer->data + sizeof(*location_function_comm);
595 binary_path_src = function_name_src +
596 location_function_comm->function_name_len;
597
598 if (function_name_src[location_function_comm->function_name_len - 1] != '\0') {
599 ret = -LTTNG_ERR_INVALID;
600 goto end;
601 }
602 if (binary_path_src[location_function_comm->binary_path_len - 1] != '\0') {
603 ret = -LTTNG_ERR_INVALID;
604 goto end;
605 }
606
607 function_name = lttng_strndup(function_name_src, LTTNG_SYMBOL_NAME_LEN);
608 if (!function_name) {
609 PERROR("lttng_strndup");
610 goto end;
611 }
612
613 binary_path = lttng_strndup(binary_path_src, LTTNG_PATH_MAX);
614 if (!binary_path) {
615 PERROR("lttng_strndup");
616 goto end;
617 }
618
619 *location = lttng_userspace_probe_location_function_create_no_check(
620 binary_path, function_name, NULL, false);
621 if (!(*location)) {
622 ret = -LTTNG_ERR_INVALID;
623 goto end;
624 }
625
626 ret = (int) expected_size;
627 end:
628 free(function_name);
629 free(binary_path);
630 return ret;
631 }
632
633 static
634 int lttng_userspace_probe_location_lookup_method_create_from_buffer(
635 struct lttng_buffer_view *buffer,
636 struct lttng_userspace_probe_location_lookup_method **lookup_method)
637 {
638 int ret;
639 struct lttng_userspace_probe_location_lookup_method_comm *lookup_comm;
640 enum lttng_userspace_probe_location_lookup_method_type type;
641
642 assert(buffer);
643 assert(buffer->data);
644 assert(lookup_method);
645
646 if (buffer->size < sizeof(*lookup_comm)) {
647 ret = -LTTNG_ERR_INVALID;
648 goto end;
649 }
650
651 lookup_comm = (struct lttng_userspace_probe_location_lookup_method_comm *)
652 buffer->data;
653 type = (enum lttng_userspace_probe_location_lookup_method_type)
654 lookup_comm->type;
655 switch (type) {
656 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
657 *lookup_method = NULL;
658 break;
659 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
660 *lookup_method =
661 lttng_userspace_probe_location_lookup_method_function_elf_create();
662 if (!(*lookup_method)) {
663 ret = -LTTNG_ERR_INVALID;
664 goto end;
665 }
666 break;
667 default:
668 ret = -LTTNG_ERR_INVALID;
669 goto end;
670 }
671
672 ret = sizeof(*lookup_comm);
673 end:
674 return ret;
675 }
676
677 LTTNG_HIDDEN
678 int lttng_userspace_probe_location_create_from_buffer(
679 const struct lttng_buffer_view *buffer,
680 struct lttng_userspace_probe_location **location)
681 {
682 struct lttng_userspace_probe_location_lookup_method *lookup_method;
683 struct lttng_userspace_probe_location_comm *probe_location_comm;
684 enum lttng_userspace_probe_location_type type;
685 struct lttng_buffer_view lookup_method_view;
686 int consumed = 0;
687 int ret;
688
689
690 assert(buffer);
691 assert(buffer->data);
692 assert(location);
693
694 lookup_method = NULL;
695
696 if (buffer->size <= sizeof(*probe_location_comm)) {
697 ret = -LTTNG_ERR_INVALID;
698 goto end;
699 }
700
701 probe_location_comm =
702 (struct lttng_userspace_probe_location_comm *) buffer->data;
703 type = (enum lttng_userspace_probe_location_type) probe_location_comm->type;
704 consumed += sizeof(*probe_location_comm);
705
706 switch (type) {
707 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
708 {
709 struct lttng_buffer_view view = lttng_buffer_view_from_view(
710 buffer, consumed, buffer->size - consumed);
711
712 ret = lttng_userspace_probe_location_function_create_from_buffer(
713 &view, location);
714 if (ret < 0) {
715 goto end;
716 }
717 break;
718 }
719 default:
720 ret = -LTTNG_ERR_INVALID;
721 goto end;
722 }
723
724 consumed += ret;
725 if (buffer->size <= consumed) {
726 ret = -LTTNG_ERR_INVALID;
727 goto end;
728 }
729
730 lookup_method_view = lttng_buffer_view_from_view(buffer, consumed,
731 buffer->size - consumed);
732 ret = lttng_userspace_probe_location_lookup_method_create_from_buffer(
733 &lookup_method_view, &lookup_method);
734 if (ret < 0) {
735 ret = -LTTNG_ERR_INVALID;
736 goto end;
737 }
738
739 assert(lookup_method);
740 (*location)->lookup_method = lookup_method;
741 lookup_method = NULL;
742 ret += consumed;
743 end:
744 return ret;
745 }
746
747 LTTNG_HIDDEN
748 int lttng_userspace_probe_location_function_set_binary_fd(
749 struct lttng_userspace_probe_location *location, int binary_fd)
750 {
751 int ret = 0;
752 struct lttng_userspace_probe_location_function *function_location;
753
754 assert(location);
755 assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
756
757 function_location = container_of(location,
758 struct lttng_userspace_probe_location_function, parent);
759 if (function_location->binary_fd >= 0) {
760 ret = close(function_location->binary_fd);
761 if (ret) {
762 PERROR("close");
763 ret = -LTTNG_ERR_INVALID;
764 goto end;
765 }
766 }
767
768 function_location->binary_fd = binary_fd;
769 end:
770 return ret;
771 }
772
773 static
774 int lttng_userspace_probe_location_function_flatten(
775 const struct lttng_userspace_probe_location *location,
776 struct lttng_dynamic_buffer *buffer)
777 {
778 struct lttng_userspace_probe_location_lookup_method_elf flat_lookup_method;
779 struct lttng_userspace_probe_location_function *probe_function;
780 struct lttng_userspace_probe_location_function flat_probe;
781 size_t function_name_len, binary_path_len;
782 size_t padding_needed = 0;
783 char *flat_probe_start;
784 int storage_needed = 0;
785 int ret;
786
787 assert(location);
788
789 if (location->lookup_method && location->lookup_method->type !=
790 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF) {
791 ret = -LTTNG_ERR_INVALID;
792 goto end;
793 }
794
795 probe_function = container_of(location,
796 struct lttng_userspace_probe_location_function,
797 parent);
798 assert(probe_function->function_name);
799 assert(probe_function->binary_path);
800
801 storage_needed +=
802 sizeof(struct lttng_userspace_probe_location_function);
803 function_name_len = strlen(probe_function->function_name) + 1;
804 binary_path_len = strlen(probe_function->binary_path) + 1;
805 storage_needed += function_name_len + binary_path_len;
806
807 /*
808 * The lookup method is aligned to 64-bit within the buffer.
809 * This is needed even if there is no lookup method since
810 * the next structure in the buffer probably needs to be
811 * aligned too (depending on the arch).
812 */
813 padding_needed = ALIGN_TO(storage_needed, sizeof(uint64_t)) - storage_needed;
814 storage_needed += padding_needed;
815
816 if (location->lookup_method) {
817 /* NOTE: elf look-up method is assumed here. */
818 storage_needed += sizeof(struct lttng_userspace_probe_location_lookup_method_elf);
819 }
820
821 if (!buffer) {
822 ret = storage_needed;
823 goto end;
824 }
825
826 if (lttng_dynamic_buffer_get_capacity_left(buffer) < storage_needed) {
827 ret = lttng_dynamic_buffer_set_capacity(buffer,
828 buffer->size + storage_needed);
829 if (ret) {
830 goto end;
831 }
832 }
833
834 memset(&flat_probe, 0, sizeof(flat_probe));
835
836 flat_probe_start = buffer->data + buffer->size;
837 flat_probe.parent.type = location->type;
838 /*
839 * The lookup method, if present, is the last element in the flat
840 * representation of the probe.
841 */
842 if (location->lookup_method) {
843 flat_probe.parent.lookup_method =
844 (struct lttng_userspace_probe_location_lookup_method *)
845 (flat_probe_start + sizeof(flat_probe) +
846 function_name_len + binary_path_len + padding_needed);
847 } else {
848 flat_probe.parent.lookup_method = NULL;
849 }
850
851 flat_probe.function_name = flat_probe_start + sizeof(flat_probe);
852 flat_probe.binary_path = flat_probe.function_name + function_name_len;
853 flat_probe.binary_fd = -1;
854 ret = lttng_dynamic_buffer_append(buffer, &flat_probe,
855 sizeof(flat_probe));
856 if (ret) {
857 goto end;
858 }
859
860 ret = lttng_dynamic_buffer_append(buffer,
861 probe_function->function_name, function_name_len);
862 if (ret) {
863 goto end;
864 }
865 ret = lttng_dynamic_buffer_append(buffer,
866 probe_function->binary_path, binary_path_len);
867 if (ret) {
868 goto end;
869 }
870
871 /* Insert padding before the lookup method. */
872 ret = lttng_dynamic_buffer_set_size(buffer,
873 buffer->size + padding_needed);
874 if (ret) {
875 goto end;
876 }
877
878 if (!location->lookup_method) {
879 /* Not an error, the default method is used. */
880 ret = storage_needed;
881 goto end;
882 }
883
884 memset(&flat_lookup_method, 0, sizeof(flat_lookup_method));
885 flat_lookup_method.parent.type =
886 LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF;
887 ret = lttng_dynamic_buffer_append(buffer,
888 &flat_lookup_method, sizeof(flat_lookup_method));
889 if (ret) {
890 goto end;
891 }
892 ret = storage_needed;
893 end:
894 return ret;
895 }
896
897 LTTNG_HIDDEN
898 int lttng_userspace_probe_location_flatten(
899 const struct lttng_userspace_probe_location *location,
900 struct lttng_dynamic_buffer *buffer)
901 {
902 int ret;
903 if (!location) {
904 ret = -LTTNG_ERR_INVALID;
905 goto end;
906 }
907
908 /* Only types currently supported. */
909 switch (location->type) {
910 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
911 ret = lttng_userspace_probe_location_function_flatten(location, buffer);
912 break;
913 default:
914 ret = -LTTNG_ERR_INVALID;
915 goto end;
916 }
917
918 end:
919 return ret;
920 }
921
922 LTTNG_HIDDEN
923 struct lttng_userspace_probe_location *lttng_userspace_probe_location_copy(
924 const struct lttng_userspace_probe_location *location)
925 {
926 struct lttng_userspace_probe_location *new_location = NULL;
927 enum lttng_userspace_probe_location_type type;
928
929 if (!location) {
930 goto err;
931 }
932
933 type = lttng_userspace_probe_location_get_type(location);
934 switch (type) {
935 case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
936 new_location =
937 lttng_userspace_probe_location_function_copy(location);
938 if (!new_location) {
939 goto err;
940 }
941 break;
942 default:
943 new_location = NULL;
944 goto err;
945 }
946 err:
947 return new_location;
948 }
This page took 0.049297 seconds and 5 git commands to generate.