2 * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/error.h>
10 #include <common/macros.h>
12 #include <lttng/condition/condition-internal.h>
13 #include <lttng/condition/event-rule-internal.h>
14 #include <lttng/condition/event-rule.h>
15 #include <lttng/event-expr-internal.h>
16 #include <lttng/event-expr.h>
17 #include <lttng/event-rule/event-rule-internal.h>
20 #include <vendor/msgpack/msgpack.h>
22 #define IS_EVENT_RULE_CONDITION(condition) \
23 (lttng_condition_get_type(condition) == \
24 LTTNG_CONDITION_TYPE_EVENT_RULE_HIT)
26 static bool is_event_rule_evaluation(const struct lttng_evaluation
*evaluation
)
28 enum lttng_condition_type type
= lttng_evaluation_get_type(evaluation
);
30 return type
== LTTNG_CONDITION_TYPE_EVENT_RULE_HIT
;
33 static bool lttng_condition_event_rule_validate(
34 const struct lttng_condition
*condition
);
35 static int lttng_condition_event_rule_serialize(
36 const struct lttng_condition
*condition
,
37 struct lttng_payload
*payload
);
38 static bool lttng_condition_event_rule_is_equal(
39 const struct lttng_condition
*_a
,
40 const struct lttng_condition
*_b
);
41 static void lttng_condition_event_rule_destroy(
42 struct lttng_condition
*condition
);
44 static bool lttng_condition_event_rule_validate(
45 const struct lttng_condition
*condition
)
48 struct lttng_condition_event_rule
*event_rule
;
54 event_rule
= container_of(
55 condition
, struct lttng_condition_event_rule
, parent
);
56 if (!event_rule
->rule
) {
57 ERR("Invalid event rule condition: a rule must be set.");
61 valid
= lttng_event_rule_validate(event_rule
->rule
);
67 * Serializes the C string `str` into `buf`.
69 * Encoding is the length of `str` plus one (for the null character),
70 * and then the string, including its null terminator.
73 int serialize_cstr(const char *str
, struct lttng_dynamic_buffer
*buf
)
76 const uint32_t len
= strlen(str
) + 1;
78 /* Serialize the length, including the null terminator. */
79 DBG("Serializing C string's length (including null terminator): "
81 ret
= lttng_dynamic_buffer_append(buf
, &len
, sizeof(len
));
86 /* Serialize the string. */
87 DBG("Serializing C string: '%s'", str
);
88 ret
= lttng_dynamic_buffer_append(buf
, str
, len
);
98 * Serializes the event expression `expr` into `buf`.
101 int serialize_event_expr(const struct lttng_event_expr
*expr
,
102 struct lttng_payload
*payload
)
104 const uint8_t type
= expr
->type
;
107 /* Serialize the expression's type. */
108 DBG("Serializing event expression's type: %d", expr
->type
);
109 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &type
, sizeof(type
));
114 /* Serialize the expression */
115 switch (expr
->type
) {
116 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD
:
117 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD
:
119 const struct lttng_event_expr_field
*field_expr
=
121 const struct lttng_event_expr_field
,
124 /* Serialize the field name. */
125 DBG("Serializing field event expression's field name: '%s'",
127 ret
= serialize_cstr(field_expr
->name
, &payload
->buffer
);
134 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD
:
136 const struct lttng_event_expr_app_specific_context_field
*field_expr
=
138 const struct lttng_event_expr_app_specific_context_field
,
141 /* Serialize the provider name. */
142 DBG("Serializing app-specific context field event expression's "
143 "provider name: '%s'",
144 field_expr
->provider_name
);
145 ret
= serialize_cstr(field_expr
->provider_name
, &payload
->buffer
);
150 /* Serialize the type name. */
151 DBG("Serializing app-specific context field event expression's "
153 field_expr
->provider_name
);
154 ret
= serialize_cstr(field_expr
->type_name
, &payload
->buffer
);
161 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT
:
163 const struct lttng_event_expr_array_field_element
*elem_expr
=
165 const struct lttng_event_expr_array_field_element
,
167 const uint32_t index
= elem_expr
->index
;
169 /* Serialize the index. */
170 DBG("Serializing array field element event expression's "
171 "index: %u", elem_expr
->index
);
172 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &index
, sizeof(index
));
177 /* Serialize the parent array field expression. */
178 DBG("Serializing array field element event expression's "
179 "parent array field event expression.");
180 ret
= serialize_event_expr(elem_expr
->array_field_expr
, payload
);
195 static int lttng_condition_event_rule_serialize(
196 const struct lttng_condition
*condition
,
197 struct lttng_payload
*payload
)
200 struct lttng_condition_event_rule
*event_rule
;
201 /* Used for iteration and communication (size matters). */
202 uint32_t i
, capture_descr_count
;
204 if (!condition
|| !IS_EVENT_RULE_CONDITION(condition
)) {
209 DBG("Serializing event rule condition");
210 event_rule
= container_of(
211 condition
, struct lttng_condition_event_rule
, parent
);
213 DBG("Serializing event rule condition's event rule");
214 ret
= lttng_event_rule_serialize(event_rule
->rule
, payload
);
219 capture_descr_count
= lttng_dynamic_pointer_array_get_count(
220 &event_rule
->capture_descriptors
);
221 DBG("Serializing event rule condition's capture descriptor count: %" PRIu32
,
222 capture_descr_count
);
223 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &capture_descr_count
,
224 sizeof(capture_descr_count
));
229 for (i
= 0; i
< capture_descr_count
; i
++) {
230 const struct lttng_event_expr
*expr
=
231 lttng_dynamic_pointer_array_get_pointer(
232 &event_rule
->capture_descriptors
, i
);
234 DBG("Serializing event rule condition's capture descriptor %" PRIu32
,
236 ret
= serialize_event_expr(expr
, payload
);
247 bool capture_descriptors_are_equal(
248 const struct lttng_condition_event_rule
*condition_a
,
249 const struct lttng_condition_event_rule
*condition_b
)
251 bool is_equal
= true;
252 size_t capture_descr_count_a
;
253 size_t capture_descr_count_b
;
256 capture_descr_count_a
= lttng_dynamic_pointer_array_get_count(
257 &condition_a
->capture_descriptors
);
258 capture_descr_count_b
= lttng_dynamic_pointer_array_get_count(
259 &condition_b
->capture_descriptors
);
261 if (capture_descr_count_a
!= capture_descr_count_b
) {
265 for (i
= 0; i
< capture_descr_count_a
; i
++) {
266 const struct lttng_event_expr
*expr_a
=
267 lttng_dynamic_pointer_array_get_pointer(
268 &condition_a
->capture_descriptors
,
270 const struct lttng_event_expr
*expr_b
=
271 lttng_dynamic_pointer_array_get_pointer(
272 &condition_b
->capture_descriptors
,
275 if (!lttng_event_expr_is_equal(expr_a
, expr_b
)) {
289 static bool lttng_condition_event_rule_is_equal(
290 const struct lttng_condition
*_a
,
291 const struct lttng_condition
*_b
)
293 bool is_equal
= false;
294 struct lttng_condition_event_rule
*a
, *b
;
296 a
= container_of(_a
, struct lttng_condition_event_rule
, parent
);
297 b
= container_of(_b
, struct lttng_condition_event_rule
, parent
);
299 /* Both event rules must be set or both must be unset. */
300 if ((a
->rule
&& !b
->rule
) || (!a
->rule
&& b
->rule
)) {
301 WARN("Comparing event_rule conditions with uninitialized rule");
305 is_equal
= lttng_event_rule_is_equal(a
->rule
, b
->rule
);
310 is_equal
= capture_descriptors_are_equal(a
, b
);
316 static void lttng_condition_event_rule_destroy(
317 struct lttng_condition
*condition
)
319 struct lttng_condition_event_rule
*event_rule
;
321 event_rule
= container_of(
322 condition
, struct lttng_condition_event_rule
, parent
);
324 lttng_event_rule_put(event_rule
->rule
);
325 lttng_dynamic_pointer_array_reset(&event_rule
->capture_descriptors
);
330 void destroy_event_expr(void *ptr
)
332 lttng_event_expr_destroy(ptr
);
335 struct lttng_condition
*lttng_condition_event_rule_create(
336 struct lttng_event_rule
*rule
)
338 struct lttng_condition
*parent
= NULL
;
339 struct lttng_condition_event_rule
*condition
= NULL
;
345 condition
= zmalloc(sizeof(struct lttng_condition_event_rule
));
350 lttng_condition_init(&condition
->parent
,
351 LTTNG_CONDITION_TYPE_EVENT_RULE_HIT
);
352 condition
->parent
.validate
= lttng_condition_event_rule_validate
,
353 condition
->parent
.serialize
= lttng_condition_event_rule_serialize
,
354 condition
->parent
.equal
= lttng_condition_event_rule_is_equal
,
355 condition
->parent
.destroy
= lttng_condition_event_rule_destroy
,
357 lttng_event_rule_get(rule
);
358 condition
->rule
= rule
;
361 lttng_dynamic_pointer_array_init(&condition
->capture_descriptors
,
364 parent
= &condition
->parent
;
370 uint64_t uint_from_buffer(const struct lttng_buffer_view
*view
, size_t size
,
374 const struct lttng_buffer_view uint_view
=
375 lttng_buffer_view_from_view(view
, *offset
, size
);
377 if (!lttng_buffer_view_is_valid(&uint_view
)) {
384 ret
= (uint64_t) *uint_view
.data
;
386 case sizeof(uint32_t):
390 memcpy(&u32
, uint_view
.data
, sizeof(u32
));
391 ret
= (uint64_t) u32
;
395 memcpy(&ret
, uint_view
.data
, sizeof(ret
));
408 const char *str_from_buffer(const struct lttng_buffer_view
*view
,
414 len
= uint_from_buffer(view
, sizeof(uint32_t), offset
);
415 if (len
== UINT64_C(-1)) {
419 ret
= &view
->data
[*offset
];
421 if (!lttng_buffer_view_contains_string(view
, ret
, len
)) {
436 struct lttng_event_expr
*event_expr_from_payload(
437 struct lttng_payload_view
*view
, size_t *offset
)
439 struct lttng_event_expr
*expr
= NULL
;
443 type
= uint_from_buffer(&view
->buffer
, sizeof(uint8_t), offset
);
444 if (type
== UINT64_C(-1)) {
449 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD
:
450 str
= str_from_buffer(&view
->buffer
, offset
);
455 expr
= lttng_event_expr_event_payload_field_create(str
);
457 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD
:
458 str
= str_from_buffer(&view
->buffer
, offset
);
463 expr
= lttng_event_expr_channel_context_field_create(str
);
465 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD
:
467 const char *provider_name
;
468 const char *type_name
;
470 provider_name
= str_from_buffer(&view
->buffer
, offset
);
471 if (!provider_name
) {
475 type_name
= str_from_buffer(&view
->buffer
, offset
);
480 expr
= lttng_event_expr_app_specific_context_field_create(
481 provider_name
, type_name
);
484 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT
:
486 struct lttng_event_expr
*array_field_expr
;
487 const uint64_t index
= uint_from_buffer(
488 &view
->buffer
, sizeof(uint32_t), offset
);
490 if (index
== UINT64_C(-1)) {
494 /* Array field expression is the encoded after this. */
495 array_field_expr
= event_expr_from_payload(view
, offset
);
496 if (!array_field_expr
) {
500 /* Move ownership of `array_field_expr` to new expression. */
501 expr
= lttng_event_expr_array_field_element_create(
502 array_field_expr
, (unsigned int) index
);
504 /* `array_field_expr` not moved: destroy it. */
505 lttng_event_expr_destroy(array_field_expr
);
517 lttng_event_expr_destroy(expr
);
525 ssize_t
lttng_condition_event_rule_create_from_payload(
526 struct lttng_payload_view
*view
,
527 struct lttng_condition
**_condition
)
529 ssize_t consumed_length
;
531 ssize_t event_rule_length
;
532 uint32_t i
, capture_descr_count
;
533 struct lttng_condition
*condition
= NULL
;
534 struct lttng_event_rule
*event_rule
= NULL
;
536 if (!view
|| !_condition
) {
540 /* Struct lttng_event_rule. */
542 struct lttng_payload_view event_rule_view
=
543 lttng_payload_view_from_view(view
, offset
, -1);
545 event_rule_length
= lttng_event_rule_create_from_payload(
546 &event_rule_view
, &event_rule
);
549 if (event_rule_length
< 0 || !event_rule
) {
553 /* Create condition (no capture descriptors yet) at this point. */
554 condition
= lttng_condition_event_rule_create(event_rule
);
560 /* Capture descriptor count. */
561 assert(event_rule_length
>= 0);
562 offset
+= (size_t) event_rule_length
;
563 capture_descr_count
= uint_from_buffer(&view
->buffer
, sizeof(uint32_t), &offset
);
564 if (capture_descr_count
== UINT32_C(-1)) {
568 /* Capture descriptors. */
569 for (i
= 0; i
< capture_descr_count
; i
++) {
570 struct lttng_event_expr
*expr
= event_expr_from_payload(
572 enum lttng_condition_status status
;
578 /* Move ownership of `expr` to `condition`. */
579 status
= lttng_condition_event_rule_append_capture_descriptor(
581 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
582 /* `expr` not moved: destroy it. */
583 lttng_event_expr_destroy(expr
);
588 consumed_length
= (ssize_t
) offset
;
589 *_condition
= condition
;
594 consumed_length
= -1;
597 lttng_event_rule_put(event_rule
);
598 lttng_condition_put(condition
);
599 return consumed_length
;
603 enum lttng_condition_status
lttng_condition_event_rule_borrow_rule_mutable(
604 const struct lttng_condition
*condition
,
605 struct lttng_event_rule
**rule
)
607 struct lttng_condition_event_rule
*event_rule
;
608 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
610 if (!condition
|| !IS_EVENT_RULE_CONDITION(condition
) || !rule
) {
611 status
= LTTNG_CONDITION_STATUS_INVALID
;
615 event_rule
= container_of(
616 condition
, struct lttng_condition_event_rule
, parent
);
617 if (!event_rule
->rule
) {
618 status
= LTTNG_CONDITION_STATUS_UNSET
;
622 *rule
= event_rule
->rule
;
627 enum lttng_condition_status
lttng_condition_event_rule_get_rule(
628 const struct lttng_condition
*condition
,
629 const struct lttng_event_rule
**rule
)
631 struct lttng_event_rule
*mutable_rule
= NULL
;
632 const enum lttng_condition_status status
=
633 lttng_condition_event_rule_borrow_rule_mutable(
634 condition
, &mutable_rule
);
636 *rule
= mutable_rule
;
640 enum lttng_condition_status
641 lttng_condition_event_rule_append_capture_descriptor(
642 struct lttng_condition
*condition
,
643 struct lttng_event_expr
*expr
)
646 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
647 struct lttng_condition_event_rule
*event_rule_cond
=
648 container_of(condition
,
649 struct lttng_condition_event_rule
, parent
);
651 /* Only accept l-values. */
652 if (!condition
|| !IS_EVENT_RULE_CONDITION(condition
) || !expr
||
653 !lttng_event_expr_is_lvalue(expr
)) {
654 status
= LTTNG_CONDITION_STATUS_INVALID
;
658 ret
= lttng_dynamic_pointer_array_add_pointer(
659 &event_rule_cond
->capture_descriptors
, expr
);
661 status
= LTTNG_CONDITION_STATUS_ERROR
;
669 enum lttng_condition_status
670 lttng_condition_event_rule_get_capture_descriptor_count(
671 const struct lttng_condition
*condition
, unsigned int *count
)
673 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
674 const struct lttng_condition_event_rule
*event_rule_cond
=
675 container_of(condition
,
676 const struct lttng_condition_event_rule
,
679 if (!condition
|| !IS_EVENT_RULE_CONDITION(condition
) || !count
) {
680 status
= LTTNG_CONDITION_STATUS_INVALID
;
684 *count
= lttng_dynamic_pointer_array_get_count(
685 &event_rule_cond
->capture_descriptors
);
691 const struct lttng_event_expr
*
692 lttng_condition_event_rule_get_capture_descriptor_at_index(
693 const struct lttng_condition
*condition
, unsigned int index
)
695 const struct lttng_condition_event_rule
*event_rule_cond
=
696 container_of(condition
,
697 const struct lttng_condition_event_rule
,
699 const struct lttng_event_expr
*expr
= NULL
;
701 if (!condition
|| !IS_EVENT_RULE_CONDITION(condition
) ||
702 index
>= lttng_dynamic_pointer_array_get_count(
703 &event_rule_cond
->capture_descriptors
)) {
707 expr
= lttng_dynamic_pointer_array_get_pointer(
708 &event_rule_cond
->capture_descriptors
, index
);
715 ssize_t
lttng_evaluation_event_rule_create_from_payload(
716 struct lttng_payload_view
*view
,
717 struct lttng_evaluation
**_evaluation
)
719 ssize_t ret
, offset
= 0;
720 const char *trigger_name
;
721 struct lttng_evaluation
*evaluation
= NULL
;
722 const struct lttng_evaluation_event_rule_comm
*header
;
723 const struct lttng_payload_view header_view
=
724 lttng_payload_view_from_view(
725 view
, 0, sizeof(*header
));
732 if (!lttng_payload_view_is_valid(&header_view
)) {
733 ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain header");
738 header
= (typeof(header
)) header_view
.buffer
.data
;
740 /* Map the originating trigger's name. */
741 offset
+= sizeof(*header
);
743 struct lttng_payload_view current_view
=
744 lttng_payload_view_from_view(view
, offset
,
745 header
->trigger_name_length
);
747 if (!lttng_payload_view_is_valid(¤t_view
)) {
748 ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain trigger name");
753 trigger_name
= current_view
.buffer
.data
;
754 if (!lttng_buffer_view_contains_string(¤t_view
.buffer
,
755 trigger_name
, header
->trigger_name_length
)) {
756 ERR("Failed to initialize from malformed event rule evaluation: invalid trigger name");
762 offset
+= header
->trigger_name_length
;
764 evaluation
= lttng_evaluation_event_rule_create(trigger_name
);
770 *_evaluation
= evaluation
;
775 lttng_evaluation_destroy(evaluation
);
779 static int lttng_evaluation_event_rule_serialize(
780 const struct lttng_evaluation
*evaluation
,
781 struct lttng_payload
*payload
)
784 struct lttng_evaluation_event_rule
*hit
;
785 struct lttng_evaluation_event_rule_comm comm
;
788 evaluation
, struct lttng_evaluation_event_rule
, parent
);
791 comm
.trigger_name_length
= strlen(hit
->name
) + 1;
793 ret
= lttng_dynamic_buffer_append(
794 &payload
->buffer
, &comm
, sizeof(comm
));
799 ret
= lttng_dynamic_buffer_append(
800 &payload
->buffer
, hit
->name
, comm
.trigger_name_length
);
805 static void lttng_evaluation_event_rule_destroy(
806 struct lttng_evaluation
*evaluation
)
808 struct lttng_evaluation_event_rule
*hit
;
811 evaluation
, struct lttng_evaluation_event_rule
, parent
);
817 struct lttng_evaluation
*lttng_evaluation_event_rule_create(
818 const char *trigger_name
)
820 struct lttng_evaluation_event_rule
*hit
;
821 struct lttng_evaluation
*evaluation
= NULL
;
823 hit
= zmalloc(sizeof(struct lttng_evaluation_event_rule
));
828 hit
->name
= strdup(trigger_name
);
833 hit
->parent
.type
= LTTNG_CONDITION_TYPE_EVENT_RULE_HIT
;
834 hit
->parent
.serialize
= lttng_evaluation_event_rule_serialize
;
835 hit
->parent
.destroy
= lttng_evaluation_event_rule_destroy
;
837 evaluation
= &hit
->parent
;
842 lttng_evaluation_event_rule_destroy(&hit
->parent
);
848 enum lttng_evaluation_status
lttng_evaluation_event_rule_get_trigger_name(
849 const struct lttng_evaluation
*evaluation
, const char **name
)
851 struct lttng_evaluation_event_rule
*hit
;
852 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
854 if (!evaluation
|| !is_event_rule_evaluation(evaluation
) || !name
) {
855 status
= LTTNG_EVALUATION_STATUS_INVALID
;
860 evaluation
, struct lttng_evaluation_event_rule
, parent
);