0f6ac9a8c1d306a7a3144f139c00461c1792349e
[lttng-tools.git] / src / common / event.c
1 /*
2 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include "common/compat/string.h"
9 #include "common/macros.h"
10 #include "lttng/lttng-error.h"
11 #include <assert.h>
12 #include <common/buffer-view.h>
13 #include <common/dynamic-array.h>
14 #include <common/dynamic-buffer.h>
15 #include <common/error.h>
16 #include <common/sessiond-comm/sessiond-comm.h>
17 #include <lttng/constant.h>
18 #include <lttng/event-internal.h>
19 #include <lttng/event.h>
20 #include <lttng/userspace-probe-internal.h>
21 #include <stdint.h>
22 #include <string.h>
23
24 struct event_list_element {
25 struct lttng_event *event;
26 struct lttng_event_exclusion *exclusions;
27 char *filter_expression;
28 };
29
30 static void event_list_destructor(void *ptr)
31 {
32 struct event_list_element *element = (struct event_list_element *) ptr;
33
34 free(element->filter_expression);
35 free(element->exclusions);
36 lttng_event_destroy(element->event);
37 free(element);
38 }
39
40 LTTNG_HIDDEN
41 struct lttng_event *lttng_event_copy(const struct lttng_event *event)
42 {
43 struct lttng_event *new_event;
44 struct lttng_event_extended *new_event_extended;
45
46 new_event = zmalloc(sizeof(*event));
47 if (!new_event) {
48 PERROR("Error allocating event structure");
49 goto end;
50 }
51
52 /* Copy the content of the old event. */
53 memcpy(new_event, event, sizeof(*event));
54
55 /*
56 * We need to create a new extended since the previous pointer is now
57 * invalid.
58 */
59 new_event_extended = zmalloc(sizeof(*new_event_extended));
60 if (!new_event_extended) {
61 PERROR("Error allocating event extended structure");
62 goto error;
63 }
64
65 new_event->extended.ptr = new_event_extended;
66 end:
67 return new_event;
68 error:
69 free(new_event);
70 new_event = NULL;
71 goto end;
72 }
73
74 static int lttng_event_probe_attr_serialize(
75 const struct lttng_event_probe_attr *probe,
76 struct lttng_dynamic_buffer *buf)
77 {
78 int ret;
79 size_t symbol_name_len;
80 struct lttng_event_probe_attr_comm comm = { 0 };
81
82 symbol_name_len = lttng_strnlen(probe->symbol_name, LTTNG_SYMBOL_NAME_LEN);
83 if (symbol_name_len == LTTNG_SYMBOL_NAME_LEN) {
84 /* Not null-termintated. */
85 ret = -1;
86 goto end;
87 }
88
89 /* Include the null terminator. */
90 symbol_name_len += 1;
91
92 comm.symbol_name_len = (uint32_t) symbol_name_len;
93 comm.addr = probe->addr;
94 comm.offset = probe->addr;
95
96 ret = lttng_dynamic_buffer_append(buf, &comm, sizeof(comm));
97 if (ret < 0) {
98 ret = -1;
99 goto end;
100 }
101
102 ret = lttng_dynamic_buffer_append(buf, probe->symbol_name, symbol_name_len);
103
104 end:
105 return ret;
106 }
107
108 static int lttng_event_function_attr_serialize(
109 const struct lttng_event_function_attr *function,
110 struct lttng_dynamic_buffer *buf)
111 {
112 int ret;
113 size_t symbol_name_len;
114 struct lttng_event_function_attr_comm comm = { 0 };
115
116 symbol_name_len = lttng_strnlen(function->symbol_name, LTTNG_SYMBOL_NAME_LEN);
117 if (symbol_name_len == LTTNG_SYMBOL_NAME_LEN) {
118 /* Not null-termintated. */
119 ret = -1;
120 goto end;
121 }
122
123 /* Include the null terminator. */
124 symbol_name_len += 1;
125
126 comm.symbol_name_len = (uint32_t) symbol_name_len;
127
128 ret = lttng_dynamic_buffer_append(buf, &comm, sizeof(comm));
129 if (ret < 0) {
130 ret = -1;
131 goto end;
132 }
133
134 ret = lttng_dynamic_buffer_append(buf, function->symbol_name, symbol_name_len);
135 end:
136 return ret;
137 }
138
139 static ssize_t lttng_event_probe_attr_create_from_buffer(
140 const struct lttng_buffer_view *view,
141 struct lttng_event_probe_attr **probe_attr)
142 {
143 ssize_t ret, offset = 0;
144 const struct lttng_event_probe_attr_comm *comm;
145 struct lttng_event_probe_attr *local_attr = NULL;
146 const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view(
147 view, offset, sizeof(*comm));
148
149 if (!lttng_buffer_view_is_valid(&comm_view)) {
150 ret = -1;
151 goto end;
152 }
153
154 comm = (typeof(comm)) view->data;
155 offset += sizeof(*comm);
156
157 local_attr = zmalloc(sizeof(*local_attr));
158 if (local_attr == NULL) {
159 ret = -1;
160 goto end;
161 }
162
163 local_attr->addr = comm->addr;
164 local_attr->offset = comm->offset;
165
166 {
167 const char *name;
168 const struct lttng_buffer_view name_view =
169 lttng_buffer_view_from_view(view, offset,
170 comm->symbol_name_len);
171 if (!lttng_buffer_view_is_valid(&name_view)) {
172 ret = -1;
173 goto end;
174 }
175
176 name = name_view.data;
177
178 if (!lttng_buffer_view_contains_string(
179 &name_view, name, comm->symbol_name_len)) {
180 ret = -1;
181 goto end;
182 }
183
184 ret = lttng_strncpy(local_attr->symbol_name, name,
185 LTTNG_SYMBOL_NAME_LEN);
186 if (ret) {
187 ret = -1;
188 goto end;
189 }
190 offset += comm->symbol_name_len;
191 }
192
193 *probe_attr = local_attr;
194 local_attr = NULL;
195 ret = offset;
196 end:
197 return ret;
198 }
199
200 static ssize_t lttng_event_function_attr_create_from_buffer(
201 const struct lttng_buffer_view *view,
202 struct lttng_event_function_attr **function_attr)
203 {
204 ssize_t ret, offset = 0;
205 const struct lttng_event_function_attr_comm *comm;
206 struct lttng_event_function_attr *local_attr = NULL;
207 const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view(
208 view, offset, sizeof(*comm));
209
210 if (!lttng_buffer_view_is_valid(&comm_view)) {
211 ret = -1;
212 goto end;
213 }
214
215 comm = (typeof(comm)) view->data;
216 offset += sizeof(*comm);
217
218 local_attr = zmalloc(sizeof(*local_attr));
219 if (local_attr == NULL) {
220 ret = -1;
221 goto end;
222 }
223
224 {
225 const char *name;
226 const struct lttng_buffer_view name_view =
227 lttng_buffer_view_from_view(view, offset,
228 comm->symbol_name_len);
229 if (!lttng_buffer_view_is_valid(&name_view)) {
230 ret = -1;
231 goto end;
232 }
233
234 name = name_view.data;
235
236 if (!lttng_buffer_view_contains_string(
237 &name_view, name, comm->symbol_name_len)) {
238 ret = -1;
239 goto end;
240 }
241
242 ret = lttng_strncpy(local_attr->symbol_name, name,
243 LTTNG_SYMBOL_NAME_LEN);
244 if (ret) {
245 ret = -1;
246 goto end;
247 }
248 offset += comm->symbol_name_len;
249 }
250
251 *function_attr = local_attr;
252 local_attr = NULL;
253 ret = offset;
254 end:
255 return ret;
256 }
257
258 static ssize_t lttng_event_exclusions_create_from_buffer(const struct lttng_buffer_view *view,
259 uint32_t count, struct lttng_event_exclusion **exclusions)
260 {
261 ssize_t ret, offset = 0;
262 size_t size = (count * LTTNG_SYMBOL_NAME_LEN);
263 uint32_t i;
264 const struct lttng_event_exclusion_comm *comm;
265 struct lttng_event_exclusion *local_exclusions;
266
267
268 local_exclusions = zmalloc(sizeof(struct lttng_event_exclusion) + size);
269 if (!local_exclusions) {
270 ret = -1;
271 goto end;
272 }
273 local_exclusions->count = count;
274
275 for (i = 0; i < count; i++) {
276 const char *string;
277 struct lttng_buffer_view string_view;
278 const struct lttng_buffer_view comm_view =
279 lttng_buffer_view_from_view(
280 view, offset, sizeof(*comm));
281
282 if (!lttng_buffer_view_is_valid(&comm_view)) {
283 ret = -1;
284 goto end;
285 }
286
287 comm = (typeof(comm)) comm_view.data;
288 offset += sizeof(*comm);
289
290 string_view = lttng_buffer_view_from_view(
291 view, offset, comm->len);
292
293 if (!lttng_buffer_view_is_valid(&string_view)) {
294 ret = -1;
295 goto end;
296 }
297
298 string = string_view.data;
299
300 if (!lttng_buffer_view_contains_string(
301 &string_view, string, comm->len)) {
302 ret = -1;
303 goto end;
304 }
305
306 ret = lttng_strncpy(
307 local_exclusions->names[i],
308 string, comm->len);
309 if (ret) {
310 ret = -1;
311 goto end;
312 }
313 offset += comm->len;
314 }
315
316 *exclusions = local_exclusions;
317 local_exclusions = NULL;
318 ret = offset;
319 end:
320 free(local_exclusions);
321 return ret;
322 }
323
324
325 LTTNG_HIDDEN
326 ssize_t lttng_event_create_from_buffer(const struct lttng_buffer_view *view,
327 struct lttng_event **event,
328 struct lttng_event_exclusion **exclusion,
329 char **filter_expression,
330 struct lttng_filter_bytecode **bytecode,
331 int sock)
332 {
333 ssize_t ret, offset = 0;
334 struct lttng_event *local_event = NULL;
335 struct lttng_event_exclusion *local_exclusions = NULL;
336 struct lttng_filter_bytecode *local_bytecode = NULL;
337 char *local_filter_expression = NULL;
338 const struct lttng_event_comm *event_comm;
339 struct lttng_event_function_attr *local_function_attr = NULL;
340 struct lttng_event_probe_attr *local_probe_attr = NULL;
341 struct lttng_userspace_probe_location *local_userspace_probe_location =
342 NULL;
343 int received_fd = -1;
344
345 /*
346 * Only event is obligatory, the other output argument are optional and
347 * depends on what the caller is interested in.
348 */
349 assert(event);
350 assert(view);
351
352 {
353 const struct lttng_buffer_view comm_view =
354 lttng_buffer_view_from_view(view, offset,
355 sizeof(*event_comm));
356
357 if (!lttng_buffer_view_is_valid(&comm_view)) {
358 ret = -1;
359 goto end;
360 }
361
362 /* lttng_event_comm header */
363 event_comm = (typeof(event_comm)) comm_view.data;
364 offset += sizeof(*event_comm);
365 }
366
367 local_event = lttng_event_create();
368 if (local_event == NULL) {
369 ret = -1;
370 goto end;
371 }
372
373 local_event->type = event_comm->event_type;
374 local_event->loglevel_type = event_comm->loglevel_type;
375 local_event->loglevel = event_comm->loglevel;
376 local_event->enabled = event_comm->enabled;
377 local_event->pid = event_comm->pid;
378 local_event->flags = event_comm->flags;
379
380 {
381 const char *name;
382 const struct lttng_buffer_view name_view =
383 lttng_buffer_view_from_view(view, offset,
384 event_comm->name_len);
385 if (!lttng_buffer_view_is_valid(&name_view)) {
386 ret = -1;
387 goto end;
388 }
389
390 name = name_view.data;
391
392 if (!lttng_buffer_view_contains_string(
393 &name_view, name, event_comm->name_len)) {
394 ret = -1;
395 goto end;
396 }
397
398 ret = lttng_strncpy(
399 local_event->name, name, LTTNG_SYMBOL_NAME_LEN);
400 if (ret) {
401 ret = -1;
402 goto end;
403 }
404 offset += event_comm->name_len;
405 }
406
407 /* Exclusions */
408 if (event_comm->exclusion_count == 0) {
409 goto deserialize_filter_expression;
410 }
411
412 {
413
414 const struct lttng_buffer_view exclusions_view =
415 lttng_buffer_view_from_view(
416 view, offset, -1);
417
418 if (!lttng_buffer_view_is_valid(&exclusions_view)) {
419 ret = -1;
420 goto end;
421 }
422
423 ret = lttng_event_exclusions_create_from_buffer(&exclusions_view,
424 event_comm->exclusion_count, &local_exclusions);
425 if (ret < 0) {
426 ret = -1;
427 goto end;
428 }
429 offset += ret;
430
431 local_event->exclusion = 1;
432 }
433
434 deserialize_filter_expression:
435
436 if (event_comm->filter_expression_len == 0) {
437 if (event_comm->bytecode_len != 0) {
438 /*
439 * This is an invalid event payload.
440 *
441 * Filter expression without bytecode is possible but
442 * not the other way around.
443 * */
444 ret = -1;
445 goto end;
446 }
447 goto deserialize_event_type_payload;
448 }
449
450 {
451 const char *filter_expression_buffer;
452 const struct lttng_buffer_view filter_expression_view =
453 lttng_buffer_view_from_view(view, offset,
454 event_comm->filter_expression_len);
455
456 if (!lttng_buffer_view_is_valid(&filter_expression_view)) {
457 ret = -1;
458 goto end;
459 }
460
461 filter_expression_buffer = filter_expression_view.data;
462
463 if (!lttng_buffer_view_contains_string(&filter_expression_view,
464 filter_expression_buffer,
465 event_comm->filter_expression_len)) {
466 ret = -1;
467 goto end;
468 }
469
470 local_filter_expression = lttng_strndup(
471 filter_expression_buffer,
472 event_comm->filter_expression_len);
473 if (!local_filter_expression) {
474 ret = -1;
475 goto end;
476 }
477
478 local_event->filter = 1;
479
480 offset += event_comm->filter_expression_len;
481 }
482
483 if (event_comm->bytecode_len == 0) {
484 /*
485 * Filter expression can be present but without bytecode
486 * when dealing with event listing.
487 */
488 goto deserialize_event_type_payload;
489 }
490
491 /* Bytecode */
492 {
493 const struct lttng_buffer_view bytecode_view =
494 lttng_buffer_view_from_view(view, offset,
495 event_comm->bytecode_len);
496
497 if (!lttng_buffer_view_is_valid(&bytecode_view)) {
498 ret = -1;
499 goto end;
500 }
501
502 local_bytecode = zmalloc(event_comm->bytecode_len);
503 if (!local_bytecode) {
504 ret = -1;
505 goto end;
506 }
507
508 memcpy(local_bytecode, bytecode_view.data,
509 event_comm->bytecode_len);
510 if ((local_bytecode->len + sizeof(*local_bytecode)) !=
511 event_comm->bytecode_len) {
512 ret = -1;
513 goto end;
514 }
515
516 offset += event_comm->bytecode_len;
517 }
518
519 deserialize_event_type_payload:
520 /* Event type specific payload */
521 switch (local_event->type) {
522 case LTTNG_EVENT_FUNCTION:
523 /* Fallthrough */
524 case LTTNG_EVENT_PROBE:
525 {
526 const struct lttng_buffer_view probe_attr_view =
527 lttng_buffer_view_from_view(view, offset,
528 event_comm->lttng_event_probe_attr_len);
529
530 if (event_comm->lttng_event_probe_attr_len == 0) {
531 ret = -1;
532 goto end;
533 }
534
535 if (!lttng_buffer_view_is_valid(&probe_attr_view)) {
536 ret = -1;
537 goto end;
538 }
539
540 ret = lttng_event_probe_attr_create_from_buffer(
541 &probe_attr_view, &local_probe_attr);
542 if (ret < 0 || ret != event_comm->lttng_event_probe_attr_len) {
543 ret = -1;
544 goto end;
545 }
546
547 /* Copy to the local event. */
548 memcpy(&local_event->attr.probe, local_probe_attr,
549 sizeof(local_event->attr.probe));
550
551 offset += ret;
552 break;
553 }
554 case LTTNG_EVENT_FUNCTION_ENTRY:
555 {
556 const struct lttng_buffer_view function_attr_view =
557 lttng_buffer_view_from_view(view, offset,
558 event_comm->lttng_event_function_attr_len);
559
560 if (event_comm->lttng_event_function_attr_len == 0) {
561 ret = -1;
562 goto end;
563 }
564
565 if (!lttng_buffer_view_is_valid(&function_attr_view)) {
566 ret = -1;
567 goto end;
568 }
569
570 ret = lttng_event_function_attr_create_from_buffer(
571 &function_attr_view, &local_function_attr);
572 if (ret < 0 || ret != event_comm->lttng_event_function_attr_len) {
573 ret = -1;
574 goto end;
575 }
576
577 /* Copy to the local event. */
578 memcpy(&local_event->attr.ftrace, local_function_attr,
579 sizeof(local_event->attr.ftrace));
580
581 offset += ret;
582
583 break;
584 }
585 case LTTNG_EVENT_USERSPACE_PROBE:
586 {
587 const struct lttng_buffer_view userspace_probe_location_view =
588 lttng_buffer_view_from_view(view, offset,
589 event_comm->userspace_probe_location_len);
590 const struct lttng_userspace_probe_location_lookup_method
591 *lookup = NULL;
592
593 if (event_comm->userspace_probe_location_len == 0) {
594 ret = -1;
595 goto end;
596 }
597
598 if (!lttng_buffer_view_is_valid(
599 &userspace_probe_location_view)) {
600 ret = -1;
601 goto end;
602 }
603
604 ret = lttng_userspace_probe_location_create_from_buffer(
605 &userspace_probe_location_view,
606 &local_userspace_probe_location);
607 if (ret < 0) {
608 WARN("Failed to create a userspace probe location from the received buffer");
609 ret = -1;
610 goto end;
611 }
612
613 if (ret != event_comm->userspace_probe_location_len) {
614 WARN("Userspace probe location from the received buffer is not the advertised length: header length = %" PRIu32 ", payload length = %lu", event_comm->userspace_probe_location_len, ret);
615 ret = -1;
616 goto end;
617 }
618
619 if (sock < 0) {
620 /*
621 * The userspace FD is simply not sent and we do not
622 * care about it. This happens on listing.
623 */
624 goto attach_userspace_probe_to_event;
625 }
626
627 /*
628 * Receive the file descriptor to the target binary from the
629 * client.
630 */
631 DBG("Receiving userspace probe target FD from client ...");
632 ret = lttcomm_recv_fds_unix_sock(sock, &received_fd, 1);
633 if (ret <= 0) {
634 DBG("Nothing recv() from client userspace probe fd... continuing");
635 ret = -1;
636 goto end;
637 }
638 /*
639 * Set the file descriptor received from the client through the
640 * unix socket in the probe location.
641 */
642 lookup = lttng_userspace_probe_location_get_lookup_method(
643 local_userspace_probe_location);
644 if (!lookup) {
645 ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
646 goto end;
647 }
648
649 /*
650 * From the kernel tracer's perspective, all userspace probe
651 * event types are all the same: a file and an offset.
652 */
653 switch (lttng_userspace_probe_location_lookup_method_get_type(
654 lookup)) {
655 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
656 ret = lttng_userspace_probe_location_function_set_binary_fd(
657 local_userspace_probe_location,
658 received_fd);
659 break;
660 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
661 ret = lttng_userspace_probe_location_tracepoint_set_binary_fd(
662 local_userspace_probe_location,
663 received_fd);
664 break;
665 default:
666 ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
667 goto end;
668 }
669
670 if (ret) {
671 ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
672 goto end;
673 }
674
675 /* Fd transfered to the object. */
676 received_fd = -1;
677
678 attach_userspace_probe_to_event:
679
680 /* Attach the probe location to the event. */
681 ret = lttng_event_set_userspace_probe_location(
682 local_event, local_userspace_probe_location);
683 if (ret) {
684 ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
685 goto end;
686 }
687
688 /*
689 * Userspace probe location object ownership transfered to the
690 * event object
691 */
692 local_userspace_probe_location = NULL;
693 offset += event_comm->userspace_probe_location_len;
694 break;
695 }
696 case LTTNG_EVENT_TRACEPOINT:
697 /* Fallthrough */
698 case LTTNG_EVENT_ALL:
699 /* Fallthrough */
700 case LTTNG_EVENT_SYSCALL:
701 /* Fallthrough */
702 case LTTNG_EVENT_NOOP:
703 /* Nothing to do here */
704 break;
705 default:
706 ret = LTTNG_ERR_UND;
707 goto end;
708 break;
709 }
710
711 /* Transfer ownership to the caller. */
712 *event = local_event;
713 local_event = NULL;
714
715 if (bytecode) {
716 *bytecode = local_bytecode;
717 local_bytecode = NULL;
718 }
719
720 if (exclusion) {
721 *exclusion = local_exclusions;
722 local_exclusions = NULL;
723 }
724
725 if (filter_expression) {
726 *filter_expression = local_filter_expression;
727 local_filter_expression = NULL;
728 }
729
730 ret = offset;
731 end:
732 lttng_event_destroy(local_event);
733 lttng_userspace_probe_location_destroy(local_userspace_probe_location);
734 free(local_filter_expression);
735 free(local_exclusions);
736 free(local_bytecode);
737 free(local_function_attr);
738 free(local_probe_attr);
739 if (received_fd > -1) {
740 if (close(received_fd)) {
741 PERROR("Failed to close received fd");
742 };
743 }
744 return ret;
745 }
746
747 LTTNG_HIDDEN
748 int lttng_event_serialize(const struct lttng_event *event,
749 unsigned int exclusion_count,
750 char **exclusion_list,
751 char *filter_expression,
752 size_t bytecode_len,
753 void *bytecode,
754 struct lttng_dynamic_buffer *buf,
755 int *fd_to_send)
756 {
757 int ret;
758 unsigned int i;
759 size_t header_offset, size_before_payload;
760 size_t name_len;
761 struct lttng_event_comm event_comm = { 0 };
762 struct lttng_event_comm *header;
763
764 assert(event);
765 assert(buf);
766
767 /* Save the header location for later in-place header update. */
768 header_offset = buf->size;
769
770 name_len = lttng_strnlen(event->name, LTTNG_SYMBOL_NAME_LEN);
771 if (name_len == LTTNG_SYMBOL_NAME_LEN) {
772 /* Event name is not NULL-terminated. */
773 ret = -1;
774 goto end;
775 }
776
777 /* Add null termination. */
778 name_len += 1;
779
780 if (exclusion_count > UINT32_MAX) {
781 /* Possible overflow. */
782 ret = -1;
783 goto end;
784 }
785
786 if (bytecode_len > UINT32_MAX) {
787 /* Possible overflow. */
788 ret = -1;
789 goto end;
790 }
791
792 event_comm.name_len = (uint32_t) name_len;
793 event_comm.event_type = (int8_t) event->type;
794 event_comm.loglevel_type = (int8_t) event->loglevel_type;
795 event_comm.loglevel = (int32_t) event->loglevel;
796 event_comm.enabled = (int8_t) event->enabled;
797 event_comm.pid = (int32_t) event->pid;
798 event_comm.exclusion_count = (uint32_t) exclusion_count;
799 event_comm.bytecode_len = (uint32_t) bytecode_len;
800 event_comm.flags = (int32_t) event->flags;
801
802 if (filter_expression) {
803 event_comm.filter_expression_len =
804 strlen(filter_expression) + 1;
805 }
806
807 /* Header */
808 ret = lttng_dynamic_buffer_append(buf, &event_comm, sizeof(event_comm));
809 if (ret) {
810 goto end;
811 }
812
813 /* Event name */
814 ret = lttng_dynamic_buffer_append(buf, event->name, name_len);
815 if (ret) {
816 goto end;
817 }
818
819 /* Exclusions */
820 for (i = 0; i < exclusion_count; i++) {
821 size_t exclusion_len;
822 struct lttng_event_exclusion_comm exclusion_comm = { 0 };
823
824 assert(exclusion_list);
825
826 exclusion_len = lttng_strnlen(
827 *(exclusion_list + i), LTTNG_SYMBOL_NAME_LEN);
828 if (exclusion_len == LTTNG_SYMBOL_NAME_LEN) {
829 /* Exclusion is not NULL-terminated. */
830 ret = -1;
831 goto end;
832 }
833
834 /* Include null terminator '\0'. */
835 exclusion_len += 1;
836
837 exclusion_comm.len = exclusion_len;
838
839 ret = lttng_dynamic_buffer_append(buf, &exclusion_comm, sizeof(exclusion_comm));
840 if (ret) {
841 goto end;
842 }
843
844 ret = lttng_dynamic_buffer_append(buf, *(exclusion_list + i),
845 exclusion_len);
846 if (ret) {
847 goto end;
848 }
849 }
850
851 /* Filter expression and its bytecode */
852 if (filter_expression) {
853 ret = lttng_dynamic_buffer_append(buf, filter_expression,
854 event_comm.filter_expression_len);
855 if (ret) {
856 goto end;
857 }
858
859 /*
860 * Bytecode can be absent when we serialize to the client
861 * for listing.
862 */
863 if (bytecode) {
864 ret = lttng_dynamic_buffer_append(
865 buf, bytecode, bytecode_len);
866 if (ret) {
867 goto end;
868 }
869 }
870 }
871
872 size_before_payload = buf->size;
873
874 /* Event type specific payload */
875 switch (event->type) {
876 case LTTNG_EVENT_FUNCTION:
877 /* Fallthrough */
878 case LTTNG_EVENT_PROBE:
879 ret = lttng_event_probe_attr_serialize(&event->attr.probe, buf);
880 if (ret) {
881 ret = -1;
882 goto end;
883 }
884
885 header = (struct lttng_event_comm *) ((char *) buf->data +
886 header_offset);
887 header->lttng_event_probe_attr_len =
888 buf->size - size_before_payload;
889
890 break;
891 case LTTNG_EVENT_FUNCTION_ENTRY:
892 ret = lttng_event_function_attr_serialize(
893 &event->attr.ftrace, buf);
894 if (ret) {
895 ret = -1;
896 goto end;
897 }
898
899 /* Update the lttng_event_function_attr len. */
900 header = (struct lttng_event_comm *) ((char *) buf->data +
901 header_offset);
902 header->lttng_event_function_attr_len =
903 buf->size - size_before_payload;
904
905 break;
906 case LTTNG_EVENT_USERSPACE_PROBE:
907 {
908 struct lttng_event_extended *ev_ext =
909 (struct lttng_event_extended *)
910 event->extended.ptr;
911 assert(event->extended.ptr);
912 assert(ev_ext->probe_location);
913
914 size_before_payload = buf->size;
915 if (ev_ext->probe_location) {
916 /*
917 * lttng_userspace_probe_location_serialize returns the
918 * number of bytes that were appended to the buffer.
919 */
920 ret = lttng_userspace_probe_location_serialize(
921 ev_ext->probe_location, buf,
922 fd_to_send);
923 if (ret < 0) {
924 goto end;
925 }
926 ret = 0;
927
928 /* Update the userspace probe location len. */
929 header = (struct lttng_event_comm *) ((char *) buf->data +
930 header_offset);
931 header->userspace_probe_location_len =
932 buf->size - size_before_payload;
933 }
934 break;
935 }
936 case LTTNG_EVENT_TRACEPOINT:
937 /* Fallthrough */
938 case LTTNG_EVENT_ALL:
939 /* Fallthrough */
940 default:
941 /* Nothing to do here */
942 break;
943 }
944
945 end:
946 return ret;
947 }
948
949 static ssize_t lttng_event_context_app_populate_from_buffer(
950 const struct lttng_buffer_view *view,
951 struct lttng_event_context *event_ctx)
952 {
953 ssize_t ret, offset = 0;
954 const struct lttng_event_context_app_comm *comm;
955 char *provider_name = NULL, *context_name = NULL;
956 size_t provider_name_len, context_name_len;
957 const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view(
958 view, offset, sizeof(*comm));
959
960 assert(event_ctx->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT);
961
962 if (!lttng_buffer_view_is_valid(&comm_view)) {
963 ret = -1;
964 goto end;
965 }
966
967 comm = (typeof(comm)) comm_view.data;
968 offset += sizeof(*comm);
969
970 provider_name_len = comm->provider_name_len;
971 context_name_len = comm->ctx_name_len;
972
973 if (provider_name_len == 0 || context_name_len == 0) {
974 /*
975 * Application provider and context names MUST
976 * be provided.
977 */
978 ret = -1;
979 goto end;
980 }
981
982 {
983 const char *name;
984 const struct lttng_buffer_view provider_name_view =
985 lttng_buffer_view_from_view(view, offset,
986 provider_name_len);
987
988 if (!lttng_buffer_view_is_valid(&provider_name_view)) {
989 ret = -1;
990 goto end;
991 }
992
993 name = provider_name_view.data;
994
995 if (!lttng_buffer_view_contains_string(&provider_name_view,
996 name, provider_name_len)) {
997 ret = -1;
998 goto end;
999 }
1000
1001 provider_name = lttng_strndup(name, provider_name_len);
1002 if (!provider_name) {
1003 ret = -1;
1004 goto end;
1005 }
1006 offset += provider_name_len;
1007 }
1008
1009 {
1010 const char *name;
1011 const struct lttng_buffer_view context_name_view =
1012 lttng_buffer_view_from_view(
1013 view, offset, context_name_len);
1014
1015 if (!lttng_buffer_view_is_valid(&context_name_view)) {
1016 ret = -1;
1017 goto end;
1018 }
1019
1020 name = context_name_view.data;
1021
1022 if (!lttng_buffer_view_contains_string(&context_name_view, name,
1023 context_name_len)) {
1024 ret = -1;
1025 goto end;
1026 }
1027
1028 context_name = lttng_strndup(name, context_name_len);
1029 if (!context_name) {
1030 ret = -1;
1031 goto end;
1032 }
1033
1034 offset += context_name_len;
1035 }
1036
1037 /* Transfer ownership of the strings */
1038 event_ctx->u.app_ctx.provider_name = provider_name;
1039 event_ctx->u.app_ctx.ctx_name = context_name;
1040 provider_name = NULL;
1041 context_name = NULL;
1042
1043 ret = offset;
1044 end:
1045 free(provider_name);
1046 free(context_name);
1047
1048 return ret;
1049 }
1050
1051 static ssize_t lttng_event_context_perf_counter_populate_from_buffer(
1052 const struct lttng_buffer_view *view,
1053 struct lttng_event_context *event_ctx)
1054 {
1055 ssize_t ret, offset = 0;
1056 const struct lttng_event_context_perf_counter_comm *comm;
1057 size_t name_len;
1058 const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view(
1059 view, offset, sizeof(*comm));
1060
1061 assert(event_ctx->ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER ||
1062 event_ctx->ctx ==
1063 LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER ||
1064 event_ctx->ctx == LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER);
1065
1066 if (!lttng_buffer_view_is_valid(&comm_view)) {
1067 ret = -1;
1068 goto end;
1069 }
1070
1071 comm = (typeof(comm)) comm_view.data;
1072 offset += sizeof(*comm);
1073
1074 name_len = comm->name_len;
1075 {
1076 const char *name;
1077 const struct lttng_buffer_view provider_name_view =
1078 lttng_buffer_view_from_view(
1079 view, offset, name_len);
1080 if (!lttng_buffer_view_is_valid(&provider_name_view)) {
1081 ret = -1;
1082 goto end;
1083 }
1084
1085 name = provider_name_view.data;
1086
1087 if (!lttng_buffer_view_contains_string(
1088 &provider_name_view, name, name_len)) {
1089 ret = -1;
1090 goto end;
1091 }
1092
1093 lttng_strncpy(event_ctx->u.perf_counter.name, name, name_len);
1094 offset += name_len;
1095 }
1096
1097 event_ctx->u.perf_counter.config = comm->config;
1098 event_ctx->u.perf_counter.type = comm->type;
1099
1100 ret = offset;
1101
1102 end:
1103 return ret;
1104 }
1105
1106 LTTNG_HIDDEN
1107 ssize_t lttng_event_context_create_from_buffer(
1108 const struct lttng_buffer_view *view,
1109 struct lttng_event_context **event_ctx)
1110 {
1111 ssize_t ret, offset = 0;
1112 const struct lttng_event_context_comm *comm;
1113 struct lttng_event_context *local_context = NULL;
1114 struct lttng_buffer_view subtype_view;
1115 struct lttng_buffer_view comm_view = lttng_buffer_view_from_view(
1116 view, offset, sizeof(*comm));
1117
1118 assert(event_ctx);
1119 assert(view);
1120
1121 if (!lttng_buffer_view_is_valid(&comm_view)) {
1122 ret = -1;
1123 goto end;
1124 }
1125
1126 comm = (typeof(comm)) comm_view.data;
1127 offset += sizeof(*comm);
1128
1129 local_context = zmalloc(sizeof(*local_context));
1130 if (!local_context) {
1131 ret = -1;
1132 goto end;
1133 }
1134
1135 local_context->ctx = comm->type;
1136
1137 subtype_view = lttng_buffer_view_from_view(view, offset, -1);
1138
1139 switch (local_context->ctx) {
1140 case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
1141 ret = lttng_event_context_app_populate_from_buffer(
1142 &subtype_view, local_context);
1143 break;
1144 case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
1145 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
1146 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
1147 ret = lttng_event_context_perf_counter_populate_from_buffer(
1148 &subtype_view, local_context);
1149 break;
1150 default:
1151 /* Nothing else to deserialize. */
1152 ret = 0;
1153 break;
1154 }
1155
1156 if (ret < 0) {
1157 goto end;
1158 }
1159
1160 offset += ret;
1161
1162 *event_ctx = local_context;
1163 local_context = NULL;
1164 ret = offset;
1165
1166 end:
1167 free(local_context);
1168 return ret;
1169 }
1170
1171 static int lttng_event_context_app_serialize(
1172 struct lttng_event_context *context,
1173 struct lttng_dynamic_buffer *buffer)
1174 {
1175 int ret;
1176 struct lttng_event_context_app_comm comm = { 0 };
1177 size_t provider_len, ctx_len;
1178 const char *provider_name;
1179 const char *ctx_name;
1180
1181 assert(buffer);
1182 assert(context);
1183 assert(context->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT);
1184
1185 provider_name = context->u.app_ctx.provider_name;
1186 ctx_name = context->u.app_ctx.ctx_name;
1187
1188 if (!provider_name || !ctx_name) {
1189 ret = -LTTNG_ERR_INVALID;
1190 goto end;
1191 }
1192
1193 provider_len = strlen(provider_name);
1194 if (provider_len == 0) {
1195 ret = -LTTNG_ERR_INVALID;
1196 goto end;
1197 }
1198
1199 /* Include the null terminator. */
1200 comm.provider_name_len = provider_len + 1;
1201
1202 ctx_len = strlen(ctx_name);
1203 if (ctx_len == 0) {
1204 ret = -LTTNG_ERR_INVALID;
1205 goto end;
1206 }
1207
1208 /* Include the null terminator. */
1209 comm.ctx_name_len = ctx_len + 1;
1210
1211 /* Header */
1212 ret = lttng_dynamic_buffer_append(buffer, &comm, sizeof(comm));
1213 if (ret) {
1214 ret = -1;
1215 goto end;
1216 }
1217
1218 ret = lttng_dynamic_buffer_append(buffer, provider_name, provider_len);
1219 if (ret) {
1220 ret = -1;
1221 goto end;
1222 }
1223 ret = lttng_dynamic_buffer_append(buffer, ctx_name, ctx_len);
1224 if (ret) {
1225 ret = -1;
1226 goto end;
1227 }
1228
1229 end:
1230 return ret;
1231 }
1232
1233 static int lttng_event_context_perf_counter_serialize(
1234 struct lttng_event_perf_counter_ctx *context,
1235 struct lttng_dynamic_buffer *buffer)
1236 {
1237 int ret;
1238 struct lttng_event_context_perf_counter_comm comm = { 0 };
1239
1240 assert(buffer);
1241 assert(context);
1242
1243 comm.config = context->config;
1244 comm.type = context->type;
1245 comm.name_len = lttng_strnlen(context->name, LTTNG_SYMBOL_NAME_LEN);
1246
1247 if (comm.name_len == LTTNG_SYMBOL_NAME_LEN) {
1248 ret = -1;
1249 goto end;
1250 }
1251
1252 /* Include the null terminator. */
1253 comm.name_len += 1;
1254
1255 /* Header */
1256 ret = lttng_dynamic_buffer_append(buffer, &comm, sizeof(comm));
1257 if (ret) {
1258 ret = -1;
1259 goto end;
1260 }
1261
1262 ret = lttng_dynamic_buffer_append(buffer, context->name, comm.name_len);
1263 if (ret) {
1264 ret = -1;
1265 goto end;
1266 }
1267
1268 end:
1269 return ret;
1270 }
1271
1272 LTTNG_HIDDEN
1273 int lttng_event_context_serialize(struct lttng_event_context *context,
1274 struct lttng_dynamic_buffer *buf)
1275 {
1276 int ret;
1277 struct lttng_event_context_comm context_comm = { 0 };
1278
1279 assert(context);
1280 assert(buf);
1281
1282 context_comm.type = (uint32_t) context->ctx;
1283
1284 /* Header */
1285 ret = lttng_dynamic_buffer_append(
1286 buf, &context_comm, sizeof(context_comm));
1287 if (ret) {
1288 goto end;
1289 }
1290
1291 switch (context->ctx) {
1292 case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
1293 ret = lttng_event_context_app_serialize(context, buf);
1294 break;
1295 case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
1296 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
1297 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
1298 ret = lttng_event_context_perf_counter_serialize(
1299 &context->u.perf_counter, buf);
1300 break;
1301 default:
1302 /* Nothing else to serialize. */
1303 break;
1304 }
1305
1306 if (ret) {
1307 goto end;
1308 }
1309
1310 end:
1311 return ret;
1312 }
1313
1314 LTTNG_HIDDEN
1315 void lttng_event_context_destroy(struct lttng_event_context *context)
1316 {
1317 if (!context) {
1318 return;
1319 }
1320
1321 if (context->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) {
1322 free(context->u.app_ctx.provider_name);
1323 free(context->u.app_ctx.ctx_name);
1324 }
1325
1326 free(context);
1327 }
1328 static enum lttng_error_code compute_flattened_size(
1329 struct lttng_dynamic_pointer_array *events, size_t *size)
1330 {
1331 enum lttng_error_code ret_code;
1332 int ret = 0;
1333 size_t storage_req, event_count, i;
1334
1335 assert(size);
1336 assert(events);
1337
1338 event_count = lttng_dynamic_pointer_array_get_count(events);
1339
1340 /* The basic struct lttng_event */
1341 storage_req = event_count * sizeof(struct lttng_event);
1342
1343 for (i = 0; i < event_count; i++) {
1344 int probe_storage_req = 0;
1345 const struct event_list_element *element =
1346 lttng_dynamic_pointer_array_get_pointer(
1347 events, i);
1348 const struct lttng_userspace_probe_location *location = NULL;
1349
1350 location = lttng_event_get_userspace_probe_location(
1351 element->event);
1352 if (location) {
1353 ret = lttng_userspace_probe_location_flatten(
1354 location, NULL);
1355 if (ret < 0) {
1356 ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
1357 goto end;
1358 }
1359
1360 probe_storage_req = ret;
1361 }
1362
1363 /* The struct·lttng_event_extended */
1364 storage_req += event_count *
1365 sizeof(struct lttng_event_extended);
1366
1367 if (element->filter_expression) {
1368 storage_req += strlen(element->filter_expression) + 1;
1369 }
1370
1371 if (element->exclusions) {
1372 storage_req += element->exclusions->count *
1373 LTTNG_SYMBOL_NAME_LEN;
1374 }
1375
1376 /* Padding to ensure the flat probe is aligned. */
1377 storage_req = ALIGN_TO(storage_req, sizeof(uint64_t));
1378 storage_req += probe_storage_req;
1379 }
1380
1381 *size = storage_req;
1382 ret_code = LTTNG_OK;
1383
1384 end:
1385 return ret_code;
1386 }
1387
1388 /*
1389 * Flatten a list of struct lttng_event.
1390 *
1391 * The buffer that is returned to the API client must contain a "flat" version
1392 * of the events that are returned. In other words, all pointers within an
1393 * lttng_event must point to a location within the returned buffer so that the
1394 * user may free everything by simply calling free() on the returned buffer.
1395 * This is needed in order to maintain API compatibility.
1396 *
1397 * A first pass is performed to compute the size of the buffer that must be
1398 * allocated. A second pass is then performed to setup the returned events so
1399 * that their members always point within the buffer.
1400 *
1401 * The layout of the returned buffer is as follows:
1402 * - struct lttng_event[nb_events],
1403 * - nb_events times the following:
1404 * - struct lttng_event_extended,
1405 * - filter_expression
1406 * - exclusions
1407 * - padding to align to 64-bits
1408 * - flattened version of userspace_probe_location
1409 */
1410 static enum lttng_error_code flatten_lttng_events(
1411 struct lttng_dynamic_pointer_array *events,
1412 struct lttng_event **flattened_events)
1413 {
1414 enum lttng_error_code ret_code;
1415 int ret, i;
1416 size_t storage_req;
1417 struct lttng_dynamic_buffer local_flattened_events;
1418 int nb_events;
1419
1420 assert(events);
1421 assert(flattened_events);
1422
1423 lttng_dynamic_buffer_init(&local_flattened_events);
1424 nb_events = lttng_dynamic_pointer_array_get_count(events);
1425
1426 ret_code = compute_flattened_size(events, &storage_req);
1427 if (ret_code != LTTNG_OK) {
1428 goto end;
1429 }
1430
1431 /*
1432 * We must ensure that "local_flattened_events" is never resized so as
1433 * to preserve the validity of the flattened objects.
1434 */
1435 ret = lttng_dynamic_buffer_set_capacity(
1436 &local_flattened_events, storage_req);
1437 if (ret) {
1438 ret_code = LTTNG_ERR_NOMEM;
1439 goto end;
1440 }
1441
1442 /* Start by laying the struct lttng_event */
1443 for (i = 0; i < nb_events; i++) {
1444 struct event_list_element *element =
1445 lttng_dynamic_pointer_array_get_pointer(
1446 events, i);
1447
1448 if (!element) {
1449 ret_code = LTTNG_ERR_FATAL;
1450 goto end;
1451 }
1452 ret = lttng_dynamic_buffer_append(&local_flattened_events,
1453 element->event, sizeof(struct lttng_event));
1454 if (ret) {
1455 ret_code = LTTNG_ERR_NOMEM;
1456 goto end;
1457 }
1458 }
1459
1460 for (i = 0; i < nb_events; i++) {
1461 struct event_list_element *element = lttng_dynamic_pointer_array_get_pointer(events, i);
1462 struct lttng_event *event = (struct lttng_event *)
1463 (local_flattened_events.data + (sizeof(struct lttng_event) * i));
1464 struct lttng_event_extended *event_extended =
1465 (struct lttng_event_extended *)
1466 (local_flattened_events.data + local_flattened_events.size);
1467 const struct lttng_userspace_probe_location *location = NULL;
1468
1469 assert(element);
1470
1471 /* Insert struct lttng_event_extended. */
1472 ret = lttng_dynamic_buffer_set_size(&local_flattened_events,
1473 local_flattened_events.size +
1474 sizeof(*event_extended));
1475 if (ret) {
1476 ret_code = LTTNG_ERR_NOMEM;
1477 goto end;
1478 }
1479 event->extended.ptr = event_extended;
1480
1481 /* Insert filter expression. */
1482 if (element->filter_expression) {
1483 size_t len = strlen(element->filter_expression) + 1;
1484
1485 event_extended->filter_expression =
1486 local_flattened_events.data +
1487 local_flattened_events.size;
1488 ret = lttng_dynamic_buffer_append(
1489 &local_flattened_events,
1490 element->filter_expression, len);
1491 if (ret) {
1492 ret_code = LTTNG_ERR_NOMEM;
1493 goto end;
1494 }
1495 }
1496
1497 /* Insert exclusions. */
1498 if (element->exclusions) {
1499 event_extended->exclusions.count =
1500 element->exclusions->count;
1501 event_extended->exclusions.strings =
1502 local_flattened_events.data +
1503 local_flattened_events.size;
1504
1505 ret = lttng_dynamic_buffer_append(
1506 &local_flattened_events,
1507 element->exclusions->names,
1508 element->exclusions->count *
1509 LTTNG_SYMBOL_NAME_LEN);
1510 if (ret) {
1511 ret_code = LTTNG_ERR_NOMEM;
1512 goto end;
1513 }
1514 }
1515
1516 /* Insert padding to align to 64-bits. */
1517 ret = lttng_dynamic_buffer_set_size(&local_flattened_events,
1518 ALIGN_TO(local_flattened_events.size,
1519 sizeof(uint64_t)));
1520 if (ret) {
1521 ret_code = LTTNG_ERR_NOMEM;
1522 goto end;
1523 }
1524
1525 location = lttng_event_get_userspace_probe_location(
1526 element->event);
1527 if (location) {
1528 event_extended->probe_location = (struct lttng_userspace_probe_location *)
1529 (local_flattened_events.data + local_flattened_events.size);
1530 ret = lttng_userspace_probe_location_flatten(
1531 location, &local_flattened_events);
1532 if (ret < 0) {
1533 ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
1534 goto end;
1535 }
1536 }
1537 }
1538
1539 /* Don't reset local_flattened_events buffer as we return its content. */
1540 *flattened_events = (struct lttng_event *) local_flattened_events.data;
1541 lttng_dynamic_buffer_init(&local_flattened_events);
1542 ret_code = LTTNG_OK;
1543 end:
1544 lttng_dynamic_buffer_reset(&local_flattened_events);
1545 return ret_code;
1546 }
1547
1548 static enum lttng_error_code event_list_create_from_buffer(
1549 const struct lttng_buffer_view *view,
1550 unsigned int count,
1551 struct lttng_dynamic_pointer_array *event_list)
1552 {
1553 enum lttng_error_code ret_code;
1554 int ret;
1555 unsigned int i;
1556 int offset = 0;
1557
1558 assert(view);
1559 assert(event_list);
1560
1561 for (i = 0; i < count; i++) {
1562 ssize_t event_size;
1563 const struct lttng_buffer_view event_view =
1564 lttng_buffer_view_from_view(view, offset, -1);
1565 struct event_list_element *element = zmalloc(sizeof(*element));
1566
1567 if (!element) {
1568 ret_code = LTTNG_ERR_NOMEM;
1569 goto end;
1570 }
1571
1572 /*
1573 * Lifetime and management of the object is now bound to the
1574 * array.
1575 */
1576 ret = lttng_dynamic_pointer_array_add_pointer(
1577 event_list, element);
1578 if (ret) {
1579 event_list_destructor(element);
1580 ret_code = LTTNG_ERR_NOMEM;
1581 goto end;
1582 }
1583
1584 /*
1585 * Bytecode is not transmitted on listing in any case we do not
1586 * care about it.
1587 */
1588 event_size = lttng_event_create_from_buffer(&event_view,
1589 &element->event,
1590 &element->exclusions,
1591 &element->filter_expression, NULL, -1);
1592 if (event_size < 0) {
1593 ret_code = LTTNG_ERR_INVALID;
1594 goto end;
1595 }
1596
1597 offset += event_size;
1598 }
1599
1600 if (view->size != offset) {
1601 ret_code = LTTNG_ERR_INVALID;
1602 goto end;
1603 }
1604
1605 ret_code = LTTNG_OK;
1606
1607 end:
1608 return ret_code;
1609 }
1610
1611 LTTNG_HIDDEN
1612 enum lttng_error_code lttng_events_create_and_flatten_from_buffer(
1613 const struct lttng_buffer_view *view,
1614 unsigned int count,
1615 struct lttng_event **events)
1616 {
1617 enum lttng_error_code ret = LTTNG_OK;
1618 struct lttng_dynamic_pointer_array local_events;
1619
1620 lttng_dynamic_pointer_array_init(&local_events, event_list_destructor);
1621
1622 /* Deserialize the events */
1623 {
1624 const struct lttng_buffer_view events_view =
1625 lttng_buffer_view_from_view(view, 0, -1);
1626
1627 ret = event_list_create_from_buffer(
1628 &events_view, count, &local_events);
1629 if (ret != LTTNG_OK) {
1630 goto end;
1631 }
1632 }
1633
1634 ret = flatten_lttng_events(&local_events, events);
1635 if (ret != LTTNG_OK) {
1636 goto end;
1637 }
1638
1639 end:
1640 lttng_dynamic_pointer_array_reset(&local_events);
1641 return ret;
1642 }
This page took 0.066307 seconds and 4 git commands to generate.