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