f6a24ef1b188286f0cbd5e32aea03c918640595d
[lttng-tools.git] / src / common / event.c
1 /*
2 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include "common/compat/string.h"
9 #include "common/macros.h"
10 #include "lttng/lttng-error.h"
11 #include <assert.h>
12 #include <common/buffer-view.h>
13 #include <common/dynamic-array.h>
14 #include <common/dynamic-buffer.h>
15 #include <common/error.h>
16 #include <common/sessiond-comm/sessiond-comm.h>
17 #include <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
25 struct event_list_element {
26 struct lttng_event *event;
27 struct lttng_event_exclusion *exclusions;
28 char *filter_expression;
29 };
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 LTTNG_HIDDEN
42 struct 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;
67 end:
68 return new_event;
69 error:
70 free(new_event);
71 new_event = NULL;
72 goto end;
73 }
74
75 static 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);
106 end:
107 return ret;
108 }
109
110 static 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);
139 end:
140 return ret;
141 }
142
143 static 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;
203 end:
204 return ret;
205 }
206
207 static ssize_t lttng_event_function_attr_create_from_payload(
208 struct lttng_payload_view *view,
209 struct lttng_event_function_attr **function_attr)
210 {
211 ssize_t ret, offset = 0;
212 const struct lttng_event_function_attr_comm *comm;
213 struct lttng_event_function_attr *local_attr = NULL;
214 struct lttng_payload_view comm_view = lttng_payload_view_from_view(
215 view, offset, sizeof(*comm));
216
217 if (!lttng_payload_view_is_valid(&comm_view)) {
218 ret = -1;
219 goto end;
220 }
221
222 comm = (typeof(comm)) view->buffer.data;
223 offset += sizeof(*comm);
224
225 local_attr = (struct lttng_event_function_attr *) zmalloc(
226 sizeof(*local_attr));
227 if (local_attr == NULL) {
228 ret = -1;
229 goto end;
230 }
231
232 {
233 const char *name;
234 struct lttng_payload_view name_view =
235 lttng_payload_view_from_view(view, offset,
236 comm->symbol_name_len);
237
238 if (!lttng_payload_view_is_valid(&name_view)) {
239 ret = -1;
240 goto end;
241 }
242
243 name = name_view.buffer.data;
244
245 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
246 comm->symbol_name_len)) {
247 ret = -1;
248 goto end;
249 }
250
251 ret = lttng_strncpy(local_attr->symbol_name, name,
252 LTTNG_SYMBOL_NAME_LEN);
253 if (ret) {
254 ret = -1;
255 goto end;
256 }
257
258 offset += comm->symbol_name_len;
259 }
260
261 *function_attr = local_attr;
262 local_attr = NULL;
263 ret = offset;
264 end:
265 return ret;
266 }
267
268 static ssize_t lttng_event_exclusions_create_from_payload(
269 struct lttng_payload_view *view,
270 uint32_t count,
271 struct lttng_event_exclusion **exclusions)
272 {
273 ssize_t ret, offset = 0;
274 size_t size = (count * LTTNG_SYMBOL_NAME_LEN);
275 uint32_t i;
276 const struct lttng_event_exclusion_comm *comm;
277 struct lttng_event_exclusion *local_exclusions;
278
279 local_exclusions = (struct lttng_event_exclusion *) zmalloc(
280 sizeof(struct lttng_event_exclusion) + size);
281 if (!local_exclusions) {
282 ret = -1;
283 goto end;
284 }
285
286 local_exclusions->count = count;
287
288 for (i = 0; i < count; i++) {
289 const char *string;
290 struct lttng_buffer_view string_view;
291 const struct lttng_buffer_view comm_view =
292 lttng_buffer_view_from_view(&view->buffer,
293 offset, sizeof(*comm));
294
295 if (!lttng_buffer_view_is_valid(&comm_view)) {
296 ret = -1;
297 goto end;
298 }
299
300 comm = (typeof(comm)) comm_view.data;
301 offset += sizeof(*comm);
302
303 string_view = lttng_buffer_view_from_view(
304 &view->buffer, offset, comm->len);
305
306 if (!lttng_buffer_view_is_valid(&string_view)) {
307 ret = -1;
308 goto end;
309 }
310
311 string = string_view.data;
312
313 if (!lttng_buffer_view_contains_string(
314 &string_view, string, comm->len)) {
315 ret = -1;
316 goto end;
317 }
318
319 ret = lttng_strncpy(local_exclusions->names[i],
320 string, LTTNG_SYMBOL_NAME_LEN);
321 if (ret) {
322 ret = -1;
323 goto end;
324 }
325
326 offset += comm->len;
327 }
328
329 *exclusions = local_exclusions;
330 local_exclusions = NULL;
331 ret = offset;
332 end:
333 free(local_exclusions);
334 return ret;
335 }
336
337 ssize_t lttng_event_create_from_payload(struct lttng_payload_view *view,
338 struct lttng_event **out_event,
339 struct lttng_event_exclusion **out_exclusion,
340 char **out_filter_expression,
341 struct lttng_bytecode **out_bytecode)
342 {
343 ssize_t ret, offset = 0;
344 struct lttng_event *local_event = NULL;
345 struct lttng_event_exclusion *local_exclusions = NULL;
346 struct lttng_bytecode *local_bytecode = NULL;
347 char *local_filter_expression = NULL;
348 const struct lttng_event_comm *event_comm;
349 struct lttng_event_function_attr *local_function_attr = NULL;
350 struct lttng_event_probe_attr *local_probe_attr = NULL;
351 struct lttng_userspace_probe_location *local_userspace_probe_location =
352 NULL;
353
354 /*
355 * Only event is obligatory, the other output argument are optional and
356 * depends on what the caller is interested in.
357 */
358 assert(out_event);
359 assert(view);
360
361 {
362 struct lttng_payload_view comm_view =
363 lttng_payload_view_from_view(view, offset,
364 sizeof(*event_comm));
365
366 if (!lttng_payload_view_is_valid(&comm_view)) {
367 ret = -1;
368 goto end;
369 }
370
371 /* lttng_event_comm header */
372 event_comm = (typeof(event_comm)) comm_view.buffer.data;
373 offset += sizeof(*event_comm);
374 }
375
376 local_event = lttng_event_create();
377 if (local_event == NULL) {
378 ret = -1;
379 goto end;
380 }
381
382 local_event->type = (enum lttng_event_type) event_comm->event_type;
383 local_event->loglevel_type = (enum lttng_loglevel_type) event_comm->loglevel_type;
384 local_event->loglevel = event_comm->loglevel;
385 local_event->enabled = event_comm->enabled;
386 local_event->pid = event_comm->pid;
387 local_event->flags = (enum lttng_event_flag) event_comm->flags;
388
389 {
390 const char *name;
391 const struct lttng_buffer_view name_view =
392 lttng_buffer_view_from_view(&view->buffer,
393 offset, event_comm->name_len);
394
395 if (!lttng_buffer_view_is_valid(&name_view)) {
396 ret = -1;
397 goto end;
398 }
399
400 name = (const char *) name_view.data;
401
402 if (!lttng_buffer_view_contains_string(
403 &name_view, name, event_comm->name_len)) {
404 ret = -1;
405 goto end;
406 }
407
408 ret = lttng_strncpy(
409 local_event->name, name, LTTNG_SYMBOL_NAME_LEN);
410 if (ret) {
411 ret = -1;
412 goto end;
413 }
414
415 offset += event_comm->name_len;
416 }
417
418 /* Exclusions */
419 if (event_comm->exclusion_count == 0) {
420 goto deserialize_filter_expression;
421 }
422
423 {
424 struct lttng_payload_view exclusions_view =
425 lttng_payload_view_from_view(
426 view, offset, -1);
427
428 if (!lttng_payload_view_is_valid(&exclusions_view)) {
429 ret = -1;
430 goto end;
431 }
432
433 ret = lttng_event_exclusions_create_from_payload(&exclusions_view,
434 event_comm->exclusion_count, &local_exclusions);
435 if (ret < 0) {
436 ret = -1;
437 goto end;
438 }
439 offset += ret;
440
441 local_event->exclusion = 1;
442 }
443
444 deserialize_filter_expression:
445
446 if (event_comm->filter_expression_len == 0) {
447 if (event_comm->bytecode_len != 0) {
448 /*
449 * This is an invalid event payload.
450 *
451 * Filter expression without bytecode is possible but
452 * not the other way around.
453 * */
454 ret = -1;
455 goto end;
456 }
457 goto deserialize_event_type_payload;
458 }
459
460 {
461 const char *filter_expression_buffer;
462 struct lttng_buffer_view filter_expression_view =
463 lttng_buffer_view_from_view(&view->buffer, offset,
464 event_comm->filter_expression_len);
465
466 if (!lttng_buffer_view_is_valid(&filter_expression_view)) {
467 ret = -1;
468 goto end;
469 }
470
471 filter_expression_buffer = filter_expression_view.data;
472
473 if (!lttng_buffer_view_contains_string(&filter_expression_view,
474 filter_expression_buffer,
475 event_comm->filter_expression_len)) {
476 ret = -1;
477 goto end;
478 }
479
480 local_filter_expression = lttng_strndup(
481 filter_expression_buffer,
482 event_comm->filter_expression_len);
483 if (!local_filter_expression) {
484 ret = -1;
485 goto end;
486 }
487
488 local_event->filter = 1;
489
490 offset += event_comm->filter_expression_len;
491 }
492
493 if (event_comm->bytecode_len == 0) {
494 /*
495 * Filter expression can be present but without bytecode
496 * when dealing with event listing.
497 */
498 goto deserialize_event_type_payload;
499 }
500
501 /* Bytecode */
502 {
503 struct lttng_payload_view bytecode_view =
504 lttng_payload_view_from_view(view, offset,
505 event_comm->bytecode_len);
506
507 if (!lttng_payload_view_is_valid(&bytecode_view)) {
508 ret = -1;
509 goto end;
510 }
511
512 local_bytecode = (struct lttng_bytecode *) zmalloc(
513 event_comm->bytecode_len);
514 if (!local_bytecode) {
515 ret = -1;
516 goto end;
517 }
518
519 memcpy(local_bytecode, bytecode_view.buffer.data,
520 event_comm->bytecode_len);
521 if ((local_bytecode->len + sizeof(*local_bytecode)) !=
522 event_comm->bytecode_len) {
523 ret = -1;
524 goto end;
525 }
526
527 offset += event_comm->bytecode_len;
528 }
529
530 deserialize_event_type_payload:
531 /* Event type specific payload */
532 switch (local_event->type) {
533 case LTTNG_EVENT_FUNCTION:
534 /* Fallthrough */
535 case LTTNG_EVENT_PROBE:
536 {
537 struct lttng_payload_view probe_attr_view =
538 lttng_payload_view_from_view(view, offset,
539 event_comm->lttng_event_probe_attr_len);
540
541 if (event_comm->lttng_event_probe_attr_len == 0) {
542 ret = -1;
543 goto end;
544 }
545
546 if (!lttng_payload_view_is_valid(&probe_attr_view)) {
547 ret = -1;
548 goto end;
549 }
550
551 ret = lttng_event_probe_attr_create_from_payload(
552 &probe_attr_view, &local_probe_attr);
553 if (ret < 0 || ret != event_comm->lttng_event_probe_attr_len) {
554 ret = -1;
555 goto end;
556 }
557
558 /* Copy to the local event. */
559 memcpy(&local_event->attr.probe, local_probe_attr,
560 sizeof(local_event->attr.probe));
561
562 offset += ret;
563 break;
564 }
565 case LTTNG_EVENT_FUNCTION_ENTRY:
566 {
567 struct lttng_payload_view function_attr_view =
568 lttng_payload_view_from_view(view, offset,
569 event_comm->lttng_event_function_attr_len);
570
571 if (event_comm->lttng_event_function_attr_len == 0) {
572 ret = -1;
573 goto end;
574 }
575
576 if (!lttng_payload_view_is_valid(&function_attr_view)) {
577 ret = -1;
578 goto end;
579 }
580
581 ret = lttng_event_function_attr_create_from_payload(
582 &function_attr_view, &local_function_attr);
583 if (ret < 0 || ret != event_comm->lttng_event_function_attr_len) {
584 ret = -1;
585 goto end;
586 }
587
588 /* Copy to the local event. */
589 memcpy(&local_event->attr.ftrace, local_function_attr,
590 sizeof(local_event->attr.ftrace));
591
592 offset += ret;
593
594 break;
595 }
596 case LTTNG_EVENT_USERSPACE_PROBE:
597 {
598 struct lttng_payload_view userspace_probe_location_view =
599 lttng_payload_view_from_view(view, offset,
600 event_comm->userspace_probe_location_len);
601
602 if (event_comm->userspace_probe_location_len == 0) {
603 ret = -1;
604 goto end;
605 }
606
607 if (!lttng_payload_view_is_valid(
608 &userspace_probe_location_view)) {
609 ret = -1;
610 goto end;
611 }
612
613 ret = lttng_userspace_probe_location_create_from_payload(
614 &userspace_probe_location_view,
615 &local_userspace_probe_location);
616 if (ret < 0) {
617 WARN("Failed to create a userspace probe location from the received buffer");
618 ret = -1;
619 goto end;
620 }
621
622 if (ret != event_comm->userspace_probe_location_len) {
623 WARN("Userspace probe location from the received buffer is not the advertised length: header length = %" PRIu32 ", payload length = %lu", event_comm->userspace_probe_location_len, ret);
624 ret = -1;
625 goto end;
626 }
627
628 /* Attach the probe location to the event. */
629 ret = lttng_event_set_userspace_probe_location(
630 local_event, local_userspace_probe_location);
631 if (ret) {
632 ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
633 goto end;
634 }
635
636 /*
637 * Userspace probe location object ownership transfered to the
638 * event object.
639 */
640 local_userspace_probe_location = NULL;
641 offset += event_comm->userspace_probe_location_len;
642 break;
643 }
644 case LTTNG_EVENT_TRACEPOINT:
645 /* Fallthrough */
646 case LTTNG_EVENT_ALL:
647 /* Fallthrough */
648 case LTTNG_EVENT_SYSCALL:
649 /* Fallthrough */
650 case LTTNG_EVENT_NOOP:
651 /* Nothing to do here */
652 break;
653 default:
654 ret = LTTNG_ERR_UND;
655 goto end;
656 break;
657 }
658
659 /* Transfer ownership to the caller. */
660 *out_event = local_event;
661 local_event = NULL;
662
663 if (out_bytecode) {
664 *out_bytecode = local_bytecode;
665 local_bytecode = NULL;
666 }
667
668 if (out_exclusion) {
669 *out_exclusion = local_exclusions;
670 local_exclusions = NULL;
671 }
672
673 if (out_filter_expression) {
674 *out_filter_expression = local_filter_expression;
675 local_filter_expression = NULL;
676 }
677
678 ret = offset;
679 end:
680 lttng_event_destroy(local_event);
681 lttng_userspace_probe_location_destroy(local_userspace_probe_location);
682 free(local_filter_expression);
683 free(local_exclusions);
684 free(local_bytecode);
685 free(local_function_attr);
686 free(local_probe_attr);
687 return ret;
688 }
689
690 int lttng_event_serialize(const struct lttng_event *event,
691 unsigned int exclusion_count,
692 char **exclusion_list,
693 char *filter_expression,
694 size_t bytecode_len,
695 struct lttng_bytecode *bytecode,
696 struct lttng_payload *payload)
697 {
698 int ret;
699 unsigned int i;
700 size_t header_offset, size_before_payload;
701 size_t name_len;
702 struct lttng_event_comm event_comm = { 0 };
703 struct lttng_event_comm *header;
704
705 assert(event);
706 assert(payload);
707 assert(exclusion_count == 0 || exclusion_list);
708
709 /* Save the header location for later in-place header update. */
710 header_offset = payload->buffer.size;
711
712 name_len = lttng_strnlen(event->name, LTTNG_SYMBOL_NAME_LEN);
713 if (name_len == LTTNG_SYMBOL_NAME_LEN) {
714 /* Event name is not NULL-terminated. */
715 ret = -1;
716 goto end;
717 }
718
719 /* Add null termination. */
720 name_len += 1;
721
722 if (exclusion_count > UINT32_MAX) {
723 /* Possible overflow. */
724 ret = -1;
725 goto end;
726 }
727
728 if (bytecode_len > UINT32_MAX) {
729 /* Possible overflow. */
730 ret = -1;
731 goto end;
732 }
733
734 event_comm.name_len = (uint32_t) name_len;
735 event_comm.event_type = (int8_t) event->type;
736 event_comm.loglevel_type = (int8_t) event->loglevel_type;
737 event_comm.loglevel = (int32_t) event->loglevel;
738 event_comm.enabled = (int8_t) event->enabled;
739 event_comm.pid = (int32_t) event->pid;
740 event_comm.exclusion_count = (uint32_t) exclusion_count;
741 event_comm.bytecode_len = (uint32_t) bytecode_len;
742 event_comm.flags = (int32_t) event->flags;
743
744 if (filter_expression) {
745 event_comm.filter_expression_len =
746 strlen(filter_expression) + 1;
747 }
748
749 /* Header */
750 ret = lttng_dynamic_buffer_append(
751 &payload->buffer, &event_comm, sizeof(event_comm));
752 if (ret) {
753 goto end;
754 }
755
756 /* Event name */
757 ret = lttng_dynamic_buffer_append(
758 &payload->buffer, event->name, name_len);
759 if (ret) {
760 goto end;
761 }
762
763 /* Exclusions */
764 for (i = 0; i < exclusion_count; i++) {
765 const size_t exclusion_len = lttng_strnlen(
766 *(exclusion_list + i), LTTNG_SYMBOL_NAME_LEN);
767 const struct lttng_event_exclusion_comm exclusion_header = {
768 .len = (uint32_t) exclusion_len + 1,
769 };
770
771 if (exclusion_len == LTTNG_SYMBOL_NAME_LEN) {
772 /* Exclusion is not NULL-terminated. */
773 ret = -1;
774 goto end;
775 }
776
777 ret = lttng_dynamic_buffer_append(&payload->buffer,
778 &exclusion_header, sizeof(exclusion_header));
779 if (ret) {
780 goto end;
781 }
782
783 ret = lttng_dynamic_buffer_append(&payload->buffer,
784 *(exclusion_list + i), exclusion_len + 1);
785 if (ret) {
786 goto end;
787 }
788 }
789
790 /* Filter expression and its bytecode */
791 if (filter_expression) {
792 ret = lttng_dynamic_buffer_append(&payload->buffer,
793 filter_expression,
794 event_comm.filter_expression_len);
795 if (ret) {
796 goto end;
797 }
798
799 /*
800 * Bytecode can be absent when we serialize to the client
801 * for listing.
802 */
803 if (bytecode) {
804 ret = lttng_dynamic_buffer_append(&payload->buffer,
805 bytecode, bytecode_len);
806 if (ret) {
807 goto end;
808 }
809 }
810 }
811
812 size_before_payload = payload->buffer.size;
813
814 /* Event type specific payload */
815 switch (event->type) {
816 case LTTNG_EVENT_FUNCTION:
817 /* Fallthrough */
818 case LTTNG_EVENT_PROBE:
819 ret = lttng_event_probe_attr_serialize(&event->attr.probe, payload);
820 if (ret) {
821 ret = -1;
822 goto end;
823 }
824
825 header = (struct lttng_event_comm *) ((char *) payload->buffer.data +
826 header_offset);
827 header->lttng_event_probe_attr_len =
828 payload->buffer.size - size_before_payload;
829
830 break;
831 case LTTNG_EVENT_FUNCTION_ENTRY:
832 ret = lttng_event_function_attr_serialize(
833 &event->attr.ftrace, payload);
834 if (ret) {
835 ret = -1;
836 goto end;
837 }
838
839 /* Update the lttng_event_function_attr len. */
840 header = (struct lttng_event_comm *) ((char *) payload->buffer.data +
841 header_offset);
842 header->lttng_event_function_attr_len =
843 payload->buffer.size - size_before_payload;
844
845 break;
846 case LTTNG_EVENT_USERSPACE_PROBE:
847 {
848 const struct lttng_event_extended *ev_ext =
849 (const struct lttng_event_extended *)
850 event->extended.ptr;
851
852 assert(event->extended.ptr);
853 assert(ev_ext->probe_location);
854
855 size_before_payload = payload->buffer.size;
856 if (ev_ext->probe_location) {
857 /*
858 * lttng_userspace_probe_location_serialize returns the
859 * number of bytes that were appended to the buffer.
860 */
861 ret = lttng_userspace_probe_location_serialize(
862 ev_ext->probe_location, payload);
863 if (ret < 0) {
864 goto end;
865 }
866
867 ret = 0;
868
869 /* Update the userspace probe location len. */
870 header = (struct lttng_event_comm *) ((char *) payload->buffer.data +
871 header_offset);
872 header->userspace_probe_location_len =
873 payload->buffer.size - size_before_payload;
874 }
875 break;
876 }
877 case LTTNG_EVENT_TRACEPOINT:
878 /* Fallthrough */
879 case LTTNG_EVENT_ALL:
880 /* Fallthrough */
881 default:
882 /* Nothing to do here. */
883 break;
884 }
885
886 end:
887 return ret;
888 }
889
890 static enum lttng_error_code compute_flattened_size(
891 struct lttng_dynamic_pointer_array *events, size_t *size)
892 {
893 enum lttng_error_code ret_code;
894 int ret = 0;
895 size_t storage_req, event_count, i;
896
897 assert(size);
898 assert(events);
899
900 event_count = lttng_dynamic_pointer_array_get_count(events);
901
902 /* The basic struct lttng_event */
903 storage_req = event_count * sizeof(struct lttng_event);
904
905 for (i = 0; i < event_count; i++) {
906 int probe_storage_req = 0;
907 const struct event_list_element *element = (const struct event_list_element *)
908 lttng_dynamic_pointer_array_get_pointer(
909 events, i);
910 const struct lttng_userspace_probe_location *location = NULL;
911
912 location = lttng_event_get_userspace_probe_location(
913 element->event);
914 if (location) {
915 ret = lttng_userspace_probe_location_flatten(
916 location, NULL);
917 if (ret < 0) {
918 ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
919 goto end;
920 }
921
922 probe_storage_req = ret;
923 }
924
925 /* The struct·lttng_event_extended */
926 storage_req += event_count *
927 sizeof(struct lttng_event_extended);
928
929 if (element->filter_expression) {
930 storage_req += strlen(element->filter_expression) + 1;
931 }
932
933 if (element->exclusions) {
934 storage_req += element->exclusions->count *
935 LTTNG_SYMBOL_NAME_LEN;
936 }
937
938 /* Padding to ensure the flat probe is aligned. */
939 storage_req = ALIGN_TO(storage_req, sizeof(uint64_t));
940 storage_req += probe_storage_req;
941 }
942
943 *size = storage_req;
944 ret_code = LTTNG_OK;
945
946 end:
947 return ret_code;
948 }
949
950 /*
951 * Flatten a list of struct lttng_event.
952 *
953 * The buffer that is returned to the API client must contain a "flat" version
954 * of the events that are returned. In other words, all pointers within an
955 * lttng_event must point to a location within the returned buffer so that the
956 * user may free everything by simply calling free() on the returned buffer.
957 * This is needed in order to maintain API compatibility.
958 *
959 * A first pass is performed to compute the size of the buffer that must be
960 * allocated. A second pass is then performed to setup the returned events so
961 * that their members always point within the buffer.
962 *
963 * The layout of the returned buffer is as follows:
964 * - struct lttng_event[nb_events],
965 * - nb_events times the following:
966 * - struct lttng_event_extended,
967 * - filter_expression
968 * - exclusions
969 * - padding to align to 64-bits
970 * - flattened version of userspace_probe_location
971 */
972 static enum lttng_error_code flatten_lttng_events(
973 struct lttng_dynamic_pointer_array *events,
974 struct lttng_event **flattened_events)
975 {
976 enum lttng_error_code ret_code;
977 int ret, i;
978 size_t storage_req;
979 struct lttng_dynamic_buffer local_flattened_events;
980 int nb_events;
981
982 assert(events);
983 assert(flattened_events);
984
985 lttng_dynamic_buffer_init(&local_flattened_events);
986 nb_events = lttng_dynamic_pointer_array_get_count(events);
987
988 ret_code = compute_flattened_size(events, &storage_req);
989 if (ret_code != LTTNG_OK) {
990 goto end;
991 }
992
993 /*
994 * We must ensure that "local_flattened_events" is never resized so as
995 * to preserve the validity of the flattened objects.
996 */
997 ret = lttng_dynamic_buffer_set_capacity(
998 &local_flattened_events, storage_req);
999 if (ret) {
1000 ret_code = LTTNG_ERR_NOMEM;
1001 goto end;
1002 }
1003
1004 /* Start by laying the struct lttng_event */
1005 for (i = 0; i < nb_events; i++) {
1006 const struct event_list_element *element = (const struct event_list_element *)
1007 lttng_dynamic_pointer_array_get_pointer(
1008 events, i);
1009
1010 if (!element) {
1011 ret_code = LTTNG_ERR_FATAL;
1012 goto end;
1013 }
1014
1015 ret = lttng_dynamic_buffer_append(&local_flattened_events,
1016 element->event, sizeof(struct lttng_event));
1017 if (ret) {
1018 ret_code = LTTNG_ERR_NOMEM;
1019 goto end;
1020 }
1021 }
1022
1023 for (i = 0; i < nb_events; i++) {
1024 const struct event_list_element *element = (const struct event_list_element *)
1025 lttng_dynamic_pointer_array_get_pointer(events, i);
1026 struct lttng_event *event = (struct lttng_event *)
1027 (local_flattened_events.data + (sizeof(struct lttng_event) * i));
1028 struct lttng_event_extended *event_extended =
1029 (struct lttng_event_extended *)
1030 (local_flattened_events.data + local_flattened_events.size);
1031 const struct lttng_userspace_probe_location *location = NULL;
1032
1033 assert(element);
1034
1035 /* Insert struct lttng_event_extended. */
1036 ret = lttng_dynamic_buffer_set_size(&local_flattened_events,
1037 local_flattened_events.size +
1038 sizeof(*event_extended));
1039 if (ret) {
1040 ret_code = LTTNG_ERR_NOMEM;
1041 goto end;
1042 }
1043 event->extended.ptr = event_extended;
1044
1045 /* Insert filter expression. */
1046 if (element->filter_expression) {
1047 const size_t len = strlen(element->filter_expression) + 1;
1048
1049 event_extended->filter_expression =
1050 local_flattened_events.data +
1051 local_flattened_events.size;
1052 ret = lttng_dynamic_buffer_append(
1053 &local_flattened_events,
1054 element->filter_expression, len);
1055 if (ret) {
1056 ret_code = LTTNG_ERR_NOMEM;
1057 goto end;
1058 }
1059 }
1060
1061 /* Insert exclusions. */
1062 if (element->exclusions) {
1063 event_extended->exclusions.count =
1064 element->exclusions->count;
1065 event_extended->exclusions.strings =
1066 local_flattened_events.data +
1067 local_flattened_events.size;
1068
1069 ret = lttng_dynamic_buffer_append(
1070 &local_flattened_events,
1071 element->exclusions->names,
1072 element->exclusions->count *
1073 LTTNG_SYMBOL_NAME_LEN);
1074 if (ret) {
1075 ret_code = LTTNG_ERR_NOMEM;
1076 goto end;
1077 }
1078 }
1079
1080 /* Insert padding to align to 64-bits. */
1081 ret = lttng_dynamic_buffer_set_size(&local_flattened_events,
1082 ALIGN_TO(local_flattened_events.size,
1083 sizeof(uint64_t)));
1084 if (ret) {
1085 ret_code = LTTNG_ERR_NOMEM;
1086 goto end;
1087 }
1088
1089 location = lttng_event_get_userspace_probe_location(
1090 element->event);
1091 if (location) {
1092 event_extended->probe_location = (struct lttng_userspace_probe_location *)
1093 (local_flattened_events.data + local_flattened_events.size);
1094 ret = lttng_userspace_probe_location_flatten(
1095 location, &local_flattened_events);
1096 if (ret < 0) {
1097 ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
1098 goto end;
1099 }
1100 }
1101 }
1102
1103 /* Don't reset local_flattened_events buffer as we return its content. */
1104 *flattened_events = (struct lttng_event *) local_flattened_events.data;
1105 lttng_dynamic_buffer_init(&local_flattened_events);
1106 ret_code = LTTNG_OK;
1107 end:
1108 lttng_dynamic_buffer_reset(&local_flattened_events);
1109 return ret_code;
1110 }
1111
1112 static enum lttng_error_code event_list_create_from_payload(
1113 struct lttng_payload_view *view,
1114 unsigned int count,
1115 struct lttng_dynamic_pointer_array *event_list)
1116 {
1117 enum lttng_error_code ret_code;
1118 int ret;
1119 unsigned int i;
1120 int offset = 0;
1121
1122 assert(view);
1123 assert(event_list);
1124
1125 for (i = 0; i < count; i++) {
1126 ssize_t event_size;
1127 struct lttng_payload_view event_view =
1128 lttng_payload_view_from_view(view, offset, -1);
1129 struct event_list_element *element =
1130 (struct event_list_element *) zmalloc(sizeof(*element));
1131
1132 if (!element) {
1133 ret_code = LTTNG_ERR_NOMEM;
1134 goto end;
1135 }
1136
1137 /*
1138 * Lifetime and management of the object is now bound to the
1139 * array.
1140 */
1141 ret = lttng_dynamic_pointer_array_add_pointer(
1142 event_list, element);
1143 if (ret) {
1144 event_list_destructor(element);
1145 ret_code = LTTNG_ERR_NOMEM;
1146 goto end;
1147 }
1148
1149 /*
1150 * Bytecode is not transmitted on listing in any case we do not
1151 * care about it.
1152 */
1153 event_size = lttng_event_create_from_payload(&event_view,
1154 &element->event,
1155 &element->exclusions,
1156 &element->filter_expression, NULL);
1157 if (event_size < 0) {
1158 ret_code = LTTNG_ERR_INVALID;
1159 goto end;
1160 }
1161
1162 offset += event_size;
1163 }
1164
1165 if (view->buffer.size != offset) {
1166 ret_code = LTTNG_ERR_INVALID_PROTOCOL;
1167 goto end;
1168 }
1169
1170 ret_code = LTTNG_OK;
1171
1172 end:
1173 return ret_code;
1174 }
1175
1176 enum lttng_error_code lttng_events_create_and_flatten_from_payload(
1177 struct lttng_payload_view *payload,
1178 unsigned int count,
1179 struct lttng_event **events)
1180 {
1181 enum lttng_error_code ret = LTTNG_OK;
1182 struct lttng_dynamic_pointer_array local_events;
1183
1184 lttng_dynamic_pointer_array_init(&local_events, event_list_destructor);
1185
1186 /* Deserialize the events. */
1187 {
1188 struct lttng_payload_view events_view =
1189 lttng_payload_view_from_view(payload, 0, -1);
1190
1191 ret = event_list_create_from_payload(
1192 &events_view, count, &local_events);
1193 if (ret != LTTNG_OK) {
1194 goto end;
1195 }
1196 }
1197
1198 ret = flatten_lttng_events(&local_events, events);
1199 if (ret != LTTNG_OK) {
1200 goto end;
1201 }
1202
1203 end:
1204 lttng_dynamic_pointer_array_reset(&local_events);
1205 return ret;
1206 }
This page took 0.057671 seconds and 3 git commands to generate.