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