lttng: Capture is only supported by tracepoint and syscall event-rules
[lttng-tools.git] / src / common / conditions / event-rule.c
index e7967e6ab2abfb3a924f73706c156bea543fe9f7..a8fd7c91282a93f12ed4601ec74061dbcdfc8285 100644 (file)
@@ -7,16 +7,22 @@
 
 #include <assert.h>
 #include <common/error.h>
+#include <common/event-expr-to-bytecode.h>
 #include <common/macros.h>
 #include <inttypes.h>
+#include <limits.h>
 #include <lttng/condition/condition-internal.h>
+#include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/condition/event-rule-internal.h>
 #include <lttng/condition/event-rule.h>
 #include <lttng/event-expr-internal.h>
 #include <lttng/event-expr.h>
+#include <lttng/event-field-value-internal.h>
 #include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/lttng-error.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <vendor/msgpack/msgpack.h>
 
 #define IS_EVENT_RULE_CONDITION(condition)      \
        (lttng_condition_get_type(condition) == \
@@ -53,7 +59,7 @@ static bool lttng_condition_event_rule_validate(
        event_rule = container_of(
                        condition, struct lttng_condition_event_rule, parent);
        if (!event_rule->rule) {
-               ERR("Invalid event rule condition: a rule must be set.");
+               ERR("Invalid event rule condition: a rule must be set");
                goto end;
        }
 
@@ -62,6 +68,52 @@ end:
        return valid;
 }
 
+static const char *msgpack_object_type_str(msgpack_object_type type)
+{
+       const char *name;
+
+       switch (type) {
+       case MSGPACK_OBJECT_NIL:
+               name = "MSGPACK_OBJECT_NIL";
+               break;
+       case MSGPACK_OBJECT_BOOLEAN:
+               name = "MSGPACK_OBJECT_BOOLEAN";
+               break;
+       case MSGPACK_OBJECT_POSITIVE_INTEGER:
+               name = "MSGPACK_OBJECT_POSITIVE_INTEGER";
+               break;
+       case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+               name = "MSGPACK_OBJECT_NEGATIVE_INTEGER";
+               break;
+       case MSGPACK_OBJECT_FLOAT32:
+               name = "MSGPACK_OBJECT_FLOAT32";
+               break;
+       case MSGPACK_OBJECT_FLOAT:
+               /* Same value as MSGPACK_OBJECT_FLOAT64 */
+               name = "MSGPACK_OBJECT_FLOAT(64)";
+               break;
+       case MSGPACK_OBJECT_STR:
+               name = "MSGPACK_OBJECT_STR";
+               break;
+       case MSGPACK_OBJECT_ARRAY:
+               name = "MSGPACK_OBJECT_ARRAY";
+               break;
+       case MSGPACK_OBJECT_MAP:
+               name = "MSGPACK_OBJECT_MAP";
+               break;
+       case MSGPACK_OBJECT_BIN:
+               name = "MSGPACK_OBJECT_BIN";
+               break;
+       case MSGPACK_OBJECT_EXT:
+               name = "MSGPACK_OBJECT_EXT";
+               break;
+       default:
+               abort();
+       }
+
+       return name;
+}
+
 /*
  * Serializes the C string `str` into `buf`.
  *
@@ -175,7 +227,7 @@ int serialize_event_expr(const struct lttng_event_expr *expr,
 
                /* Serialize the parent array field expression. */
                DBG("Serializing array field element event expression's "
-                               "parent array field event expression.");
+                               "parent array field event expression");
                ret = serialize_event_expr(elem_expr->array_field_expr, payload);
                if (ret) {
                        goto end;
@@ -191,12 +243,46 @@ end:
        return ret;
 }
 
+static
+struct lttng_capture_descriptor *
+lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+               const struct lttng_condition *condition, unsigned int index)
+{
+       const struct lttng_condition_event_rule *event_rule_cond =
+                       container_of(condition,
+                               const struct lttng_condition_event_rule,
+                               parent);
+       struct lttng_capture_descriptor *desc = NULL;
+       unsigned int count;
+       enum lttng_condition_status status;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               goto end;
+       }
+
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition, &count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       desc = lttng_dynamic_pointer_array_get_pointer(
+                       &event_rule_cond->capture_descriptors, index);
+end:
+       return desc;
+}
+
 static int lttng_condition_event_rule_serialize(
                const struct lttng_condition *condition,
                struct lttng_payload *payload)
 {
        int ret;
        struct lttng_condition_event_rule *event_rule;
+       enum lttng_condition_status status;
        /* Used for iteration and communication (size matters). */
        uint32_t i, capture_descr_count;
 
@@ -215,8 +301,13 @@ static int lttng_condition_event_rule_serialize(
                goto end;
        }
 
-       capture_descr_count = lttng_dynamic_pointer_array_get_count(
-                       &event_rule->capture_descriptors);
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition, &capture_descr_count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ret = -1;
+               goto end;
+       };
+
        DBG("Serializing event rule condition's capture descriptor count: %" PRIu32,
                        capture_descr_count);
        ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_descr_count,
@@ -226,13 +317,13 @@ static int lttng_condition_event_rule_serialize(
        }
 
        for (i = 0; i < capture_descr_count; i++) {
-               const struct lttng_event_expr *expr =
-                               lttng_dynamic_pointer_array_get_pointer(
-                                       &event_rule->capture_descriptors, i);
+               const struct lttng_capture_descriptor *desc =
+                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+                                               condition, i);
 
                DBG("Serializing event rule condition's capture descriptor %" PRIu32,
                                i);
-               ret = serialize_event_expr(expr, payload);
+               ret = serialize_event_expr(desc->event_expression, payload);
                if (ret) {
                        goto end;
                }
@@ -244,18 +335,26 @@ end:
 
 static
 bool capture_descriptors_are_equal(
-               const struct lttng_condition_event_rule *condition_a,
-               const struct lttng_condition_event_rule *condition_b)
+               const struct lttng_condition *condition_a,
+               const struct lttng_condition *condition_b)
 {
        bool is_equal = true;
-       size_t capture_descr_count_a;
-       size_t capture_descr_count_b;
+       unsigned int capture_descr_count_a;
+       unsigned int capture_descr_count_b;
        size_t i;
+       enum lttng_condition_status status;
+
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition_a, &capture_descr_count_a);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto not_equal;
+       }
 
-       capture_descr_count_a = lttng_dynamic_pointer_array_get_count(
-                       &condition_a->capture_descriptors);
-       capture_descr_count_b = lttng_dynamic_pointer_array_get_count(
-                       &condition_b->capture_descriptors);
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition_b, &capture_descr_count_b);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto not_equal;
+       }
 
        if (capture_descr_count_a != capture_descr_count_b) {
                goto not_equal;
@@ -263,12 +362,12 @@ bool capture_descriptors_are_equal(
 
        for (i = 0; i < capture_descr_count_a; i++) {
                const struct lttng_event_expr *expr_a =
-                               lttng_dynamic_pointer_array_get_pointer(
-                                       &condition_a->capture_descriptors,
+                               lttng_condition_event_rule_get_capture_descriptor_at_index(
+                                       condition_a,
                                        i);
                const struct lttng_event_expr *expr_b =
-                               lttng_dynamic_pointer_array_get_pointer(
-                                       &condition_b->capture_descriptors,
+                               lttng_condition_event_rule_get_capture_descriptor_at_index(
+                                       condition_b,
                                        i);
 
                if (!lttng_event_expr_is_equal(expr_a, expr_b)) {
@@ -306,7 +405,7 @@ static bool lttng_condition_event_rule_is_equal(
                goto end;
        }
 
-       is_equal = capture_descriptors_are_equal(a, b);
+       is_equal = capture_descriptors_are_equal(_a, _b);
 
 end:
        return is_equal;
@@ -326,9 +425,14 @@ static void lttng_condition_event_rule_destroy(
 }
 
 static
-void destroy_event_expr(void *ptr)
+void destroy_capture_descriptor(void *ptr)
 {
-       lttng_event_expr_destroy(ptr);
+       struct lttng_capture_descriptor *desc =
+                       (struct lttng_capture_descriptor *) ptr;
+
+       lttng_event_expr_destroy(desc->event_expression);
+       free(desc->bytecode);
+       free(desc);
 }
 
 struct lttng_condition *lttng_condition_event_rule_create(
@@ -358,7 +462,7 @@ struct lttng_condition *lttng_condition_event_rule_create(
        rule = NULL;
 
        lttng_dynamic_pointer_array_init(&condition->capture_descriptors,
-                       destroy_event_expr);
+                       destroy_capture_descriptor);
 
        parent = &condition->parent;
 end:
@@ -566,9 +670,9 @@ ssize_t lttng_condition_event_rule_create_from_payload(
 
        /* Capture descriptors. */
        for (i = 0; i < capture_descr_count; i++) {
+               enum lttng_condition_status status;
                struct lttng_event_expr *expr = event_expr_from_payload(
                                view, &offset);
-               enum lttng_condition_status status;
 
                if (!expr) {
                        goto error;
@@ -646,6 +750,8 @@ lttng_condition_event_rule_append_capture_descriptor(
        struct lttng_condition_event_rule *event_rule_cond =
                        container_of(condition,
                                struct lttng_condition_event_rule, parent);
+       struct lttng_capture_descriptor *descriptor = NULL;
+       const struct lttng_event_rule *rule = NULL;
 
        /* Only accept l-values. */
        if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !expr ||
@@ -654,14 +760,49 @@ lttng_condition_event_rule_append_capture_descriptor(
                goto end;
        }
 
+       status = lttng_condition_event_rule_get_rule(condition, &rule);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       switch(lttng_event_rule_get_type(rule)) {
+       case LTTNG_EVENT_RULE_TYPE_TRACEPOINT:
+       case LTTNG_EVENT_RULE_TYPE_SYSCALL:
+               /* Supported. */
+               status = LTTNG_CONDITION_STATUS_OK;
+               break;
+       case LTTNG_EVENT_RULE_TYPE_UNKNOWN:
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               break;
+       default:
+               status = LTTNG_CONDITION_STATUS_UNSUPPORTED;
+               break;
+       }
+
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       descriptor = malloc(sizeof(*descriptor));
+       if (descriptor == NULL) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+       descriptor->event_expression = expr;
+       descriptor->bytecode = NULL;
+
        ret = lttng_dynamic_pointer_array_add_pointer(
-                       &event_rule_cond->capture_descriptors, expr);
+                       &event_rule_cond->capture_descriptors, descriptor);
        if (ret) {
                status = LTTNG_CONDITION_STATUS_ERROR;
                goto end;
        }
 
+       /* Ownership is transfered to the internal capture_descriptors array */
+       descriptor = NULL;
 end:
+       free(descriptor);
        return status;
 }
 
@@ -691,20 +832,15 @@ const struct lttng_event_expr *
 lttng_condition_event_rule_get_capture_descriptor_at_index(
                const struct lttng_condition *condition, unsigned int index)
 {
-       const struct lttng_condition_event_rule *event_rule_cond =
-                       container_of(condition,
-                               const struct lttng_condition_event_rule,
-                               parent);
        const struct lttng_event_expr *expr = NULL;
+       const struct lttng_capture_descriptor *desc = NULL;
 
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition) ||
-                       index >= lttng_dynamic_pointer_array_get_count(
-                               &event_rule_cond->capture_descriptors)) {
+       desc = lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+                       condition, index);
+       if (desc == NULL) {
                goto end;
        }
-
-       expr = lttng_dynamic_pointer_array_get_pointer(
-                       &event_rule_cond->capture_descriptors, index);
+       expr = desc->event_expression;
 
 end:
        return expr;
@@ -712,6 +848,7 @@ end:
 
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_event_rule_create_from_payload(
+               const struct lttng_condition_event_rule *condition,
                struct lttng_payload_view *view,
                struct lttng_evaluation **_evaluation)
 {
@@ -722,6 +859,8 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        const struct lttng_payload_view header_view =
                        lttng_payload_view_from_view(
                                        view, 0, sizeof(*header));
+       uint32_t capture_payload_size;
+       const char *capture_payload = NULL;
 
        if (!_evaluation) {
                ret = -1;
@@ -739,7 +878,7 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        /* Map the originating trigger's name. */
        offset += sizeof(*header);
        {
-               struct lttng_payload_view current_view =
+               const struct lttng_payload_view current_view =
                                lttng_payload_view_from_view(view, offset,
                                                header->trigger_name_length);
 
@@ -759,13 +898,40 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        }
 
        offset += header->trigger_name_length;
+       {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               if (current_view.buffer.size < sizeof(capture_payload_size)) {
+                       ret = -1;
+                       goto error;
+               }
+
+               memcpy(&capture_payload_size, current_view.buffer.data,
+                               sizeof(capture_payload_size));
+       }
+       offset += sizeof(capture_payload_size);
+
+       if (capture_payload_size > 0) {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
 
-       evaluation = lttng_evaluation_event_rule_create(trigger_name);
+               if (current_view.buffer.size < capture_payload_size) {
+                       ret = -1;
+                       goto error;
+               }
+
+               capture_payload = current_view.buffer.data;
+       }
+
+       evaluation = lttng_evaluation_event_rule_create(condition, trigger_name,
+                       capture_payload, capture_payload_size, true);
        if (!evaluation) {
                ret = -1;
                goto error;
        }
 
+       offset += capture_payload_size;
        *_evaluation = evaluation;
        evaluation = NULL;
        ret = offset;
@@ -782,6 +948,7 @@ static int lttng_evaluation_event_rule_serialize(
        int ret = 0;
        struct lttng_evaluation_event_rule *hit;
        struct lttng_evaluation_event_rule_comm comm;
+       uint32_t capture_payload_size;
 
        hit = container_of(
                        evaluation, struct lttng_evaluation_event_rule, parent);
@@ -797,6 +964,68 @@ static int lttng_evaluation_event_rule_serialize(
 
        ret = lttng_dynamic_buffer_append(
                        &payload->buffer, hit->name, comm.trigger_name_length);
+       if (ret) {
+               goto end;
+       }
+
+       capture_payload_size = (uint32_t) hit->capture_payload.size;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_payload_size,
+                       sizeof(capture_payload_size));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, hit->capture_payload.data,
+                       hit->capture_payload.size);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+bool msgpack_str_is_equal(const struct msgpack_object *obj, const char *str)
+{
+       bool is_equal = true;
+
+       assert(obj->type == MSGPACK_OBJECT_STR);
+
+       if (obj->via.str.size != strlen(str)) {
+               is_equal = false;
+               goto end;
+       }
+
+       if (strncmp(obj->via.str.ptr, str, obj->via.str.size) != 0) {
+               is_equal = false;
+               goto end;
+       }
+
+end:
+       return is_equal;
+}
+
+static
+const msgpack_object *get_msgpack_map_obj(const struct msgpack_object *map_obj,
+               const char *name)
+{
+       const msgpack_object *ret = NULL;
+       size_t i;
+
+       assert(map_obj->type == MSGPACK_OBJECT_MAP);
+
+       for (i = 0; i < map_obj->via.map.size; i++) {
+               const struct msgpack_object_kv *kv = &map_obj->via.map.ptr[i];
+
+               assert(kv->key.type == MSGPACK_OBJECT_STR);
+
+               if (msgpack_str_is_equal(&kv->key, name)) {
+                       ret = &kv->val;
+                       goto end;
+               }
+       }
+
 end:
        return ret;
 }
@@ -809,24 +1038,333 @@ static void lttng_evaluation_event_rule_destroy(
        hit = container_of(
                        evaluation, struct lttng_evaluation_event_rule, parent);
        free(hit->name);
+       lttng_dynamic_buffer_reset(&hit->capture_payload);
+       lttng_event_field_value_destroy(hit->captured_values);
        free(hit);
 }
 
+static
+int event_field_value_from_obj(const msgpack_object *obj,
+               struct lttng_event_field_value **field_val)
+{
+       int ret = 0;
+
+       assert(obj);
+       assert(field_val);
+
+       switch (obj->type) {
+       case MSGPACK_OBJECT_NIL:
+               /* Unavailable. */
+               *field_val = NULL;
+               goto end;
+       case MSGPACK_OBJECT_POSITIVE_INTEGER:
+               *field_val = lttng_event_field_value_uint_create(
+                               obj->via.u64);
+               break;
+       case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+               *field_val = lttng_event_field_value_int_create(
+                               obj->via.i64);
+               break;
+       case MSGPACK_OBJECT_FLOAT32:
+       case MSGPACK_OBJECT_FLOAT64:
+               *field_val = lttng_event_field_value_real_create(
+                               obj->via.f64);
+               break;
+       case MSGPACK_OBJECT_STR:
+               *field_val = lttng_event_field_value_string_create_with_size(
+                               obj->via.str.ptr, obj->via.str.size);
+               break;
+       case MSGPACK_OBJECT_ARRAY:
+       {
+               size_t i;
+
+               *field_val = lttng_event_field_value_array_create();
+               if (!*field_val) {
+                       goto error;
+               }
+
+               for (i = 0; i < obj->via.array.size; i++) {
+                       const msgpack_object *elem_obj = &obj->via.array.ptr[i];
+                       struct lttng_event_field_value *elem_field_val;
+
+                       ret = event_field_value_from_obj(elem_obj,
+                                       &elem_field_val);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (elem_field_val) {
+                               ret = lttng_event_field_value_array_append(
+                                               *field_val, elem_field_val);
+                       } else {
+                               ret = lttng_event_field_value_array_append_unavailable(
+                                               *field_val);
+                       }
+
+                       if (ret) {
+                               lttng_event_field_value_destroy(elem_field_val);
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       case MSGPACK_OBJECT_MAP:
+       {
+               /*
+                * As of this version, the only valid map object is
+                * for an enumeration value, for example:
+                *
+                *     type: enum
+                *     value: 177
+                *     labels:
+                *     - Labatt 50
+                *     - Molson Dry
+                *     - Carling Black Label
+                */
+               const msgpack_object *inner_obj;
+               size_t label_i;
+
+               inner_obj = get_msgpack_map_obj(obj, "type");
+               if (!inner_obj) {
+                       ERR("Missing `type` entry in map object");
+                       goto error;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_STR) {
+                       ERR("Map object's `type` entry is not a string: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               if (!msgpack_str_is_equal(inner_obj, "enum")) {
+                       ERR("Map object's `type` entry: expecting `enum`");
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "value");
+               if (!inner_obj) {
+                       ERR("Missing `value` entry in map object");
+                       goto error;
+               }
+
+               if (inner_obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_uint_create(
+                                       inner_obj->via.u64);
+               } else if (inner_obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_int_create(
+                                       inner_obj->via.i64);
+               } else {
+                       ERR("Map object's `value` entry is not an integer: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               if (!*field_val) {
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "labels");
+               if (!inner_obj) {
+                       /* No labels */
+                       goto end;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_ARRAY) {
+                       ERR("Map object's `labels` entry is not an array: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               for (label_i = 0; label_i < inner_obj->via.array.size;
+                               label_i++) {
+                       int iret;
+                       const msgpack_object *elem_obj =
+                                       &inner_obj->via.array.ptr[label_i];
+
+                       if (elem_obj->type != MSGPACK_OBJECT_STR) {
+                               ERR("Map object's `labels` entry's type is not a string: type = %s",
+                                               msgpack_object_type_str(elem_obj->type));
+                               goto error;
+                       }
+
+                       iret = lttng_event_field_value_enum_append_label_with_size(
+                                       *field_val, elem_obj->via.str.ptr,
+                                       elem_obj->via.str.size);
+                       if (iret) {
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       default:
+               ERR("Unexpected object type: type = %s",
+                               msgpack_object_type_str(obj->type));
+               goto error;
+       }
+
+       if (!*field_val) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(*field_val);
+       *field_val = NULL;
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+struct lttng_event_field_value *event_field_value_from_capture_payload(
+               const struct lttng_condition_event_rule *condition,
+               const char *capture_payload, size_t capture_payload_size)
+{
+       struct lttng_event_field_value *ret = NULL;
+       msgpack_unpacked unpacked;
+       msgpack_unpack_return unpack_return;
+       const msgpack_object *root_obj;
+       const msgpack_object_array *root_array_obj;
+       size_t i;
+       size_t count;
+
+       assert(condition);
+       assert(capture_payload);
+
+       /* Initialize value. */
+       msgpack_unpacked_init(&unpacked);
+
+       /* Decode. */
+       unpack_return = msgpack_unpack_next(&unpacked, capture_payload,
+                       capture_payload_size, NULL);
+       if (unpack_return != MSGPACK_UNPACK_SUCCESS) {
+               ERR("msgpack_unpack_next() failed to decode the "
+                               "MessagePack-encoded capture payload: "
+                               "size = %zu, ret = %d",
+                               capture_payload_size, unpack_return);
+               goto error;
+       }
+
+       /* Get root array. */
+       root_obj = &unpacked.data;
+
+       if (root_obj->type != MSGPACK_OBJECT_ARRAY) {
+               ERR("Expecting an array as the root object: type = %s",
+                               msgpack_object_type_str(root_obj->type));
+               goto error;
+       }
+
+       root_array_obj = &root_obj->via.array;
+
+       /* Create an empty root array event field value. */
+       ret = lttng_event_field_value_array_create();
+       if (!ret) {
+               goto error;
+       }
+
+       /*
+        * For each capture descriptor in the condition object:
+        *
+        * 1. Get its corresponding captured field value MessagePack
+        *    object.
+        *
+        * 2. Create a corresponding event field value.
+        *
+        * 3. Append it to `ret` (the root array event field value).
+        */
+       count = lttng_dynamic_pointer_array_get_count(
+                       &condition->capture_descriptors);
+       assert(count > 0);
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_capture_descriptor *capture_descriptor =
+                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+                                               &condition->parent, i);
+               const msgpack_object *elem_obj;
+               struct lttng_event_field_value *elem_field_val;
+               int iret;
+
+               assert(capture_descriptor);
+
+               elem_obj = &root_array_obj->ptr[i];
+               iret = event_field_value_from_obj(elem_obj,
+                               &elem_field_val);
+               if (iret) {
+                       goto error;
+               }
+
+               if (elem_field_val) {
+                       iret = lttng_event_field_value_array_append(ret,
+                                       elem_field_val);
+               } else {
+                       iret = lttng_event_field_value_array_append_unavailable(
+                                       ret);
+               }
+
+               if (iret) {
+                       lttng_event_field_value_destroy(elem_field_val);
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(ret);
+       ret = NULL;
+
+end:
+       msgpack_unpacked_destroy(&unpacked);
+       return ret;
+}
+
 LTTNG_HIDDEN
 struct lttng_evaluation *lttng_evaluation_event_rule_create(
-               const char *trigger_name)
+               const struct lttng_condition_event_rule *condition,
+               const char *trigger_name,
+               const char *capture_payload, size_t capture_payload_size,
+               bool decode_capture_payload)
 {
        struct lttng_evaluation_event_rule *hit;
        struct lttng_evaluation *evaluation = NULL;
 
        hit = zmalloc(sizeof(struct lttng_evaluation_event_rule));
        if (!hit) {
-               goto end;
+               goto error;
        }
 
        hit->name = strdup(trigger_name);
        if (!hit->name) {
-               goto end;
+               goto error;
+       }
+
+       lttng_dynamic_buffer_init(&hit->capture_payload);
+
+       if (capture_payload) {
+               const int ret = lttng_dynamic_buffer_append(
+                               &hit->capture_payload, capture_payload,
+                               capture_payload_size);
+               if (ret) {
+                       ERR("Failed to initialize capture payload of event rule evaluation");
+                       goto error;
+               }
+
+               if (decode_capture_payload) {
+                       hit->captured_values =
+                                       event_field_value_from_capture_payload(
+                                               condition,
+                                               capture_payload,
+                                               capture_payload_size);
+                       if (!hit->captured_values) {
+                               ERR("Failed to decode the capture payload: size = %zu",
+                                               capture_payload_size);
+                               goto error;
+                       }
+               }
        }
 
        hit->parent.type = LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
@@ -836,7 +1374,7 @@ struct lttng_evaluation *lttng_evaluation_event_rule_create(
        evaluation = &hit->parent;
        hit = NULL;
 
-end:
+error:
        if (hit) {
                lttng_evaluation_event_rule_destroy(&hit->parent);
        }
@@ -844,6 +1382,32 @@ end:
        return evaluation;
 }
 
+enum lttng_evaluation_status lttng_evaluation_event_rule_get_captured_values(
+               const struct lttng_evaluation *evaluation,
+               const struct lttng_event_field_value **field_val)
+{
+       struct lttng_evaluation_event_rule *hit;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_event_rule_evaluation(evaluation) ||
+                       !field_val) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       hit = container_of(evaluation, struct lttng_evaluation_event_rule,
+                       parent);
+       if (!hit->captured_values) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       *field_val = hit->captured_values;
+
+end:
+       return status;
+}
+
 enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
                const struct lttng_evaluation *evaluation, const char **name)
 {
@@ -861,3 +1425,90 @@ enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
 end:
        return status;
 }
+
+LTTNG_HIDDEN
+enum lttng_error_code
+lttng_condition_event_rule_generate_capture_descriptor_bytecode(
+               struct lttng_condition *condition)
+{
+       enum lttng_error_code ret;
+       enum lttng_condition_status status;
+       unsigned int capture_count, i;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               ret = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition, &capture_count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ret = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       for (i = 0; i < capture_count; i++) {
+               struct lttng_capture_descriptor *local_capture_desc =
+                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+                                               condition, i);
+
+               if (local_capture_desc == NULL) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+
+               /* Generate the bytecode. */
+               status = lttng_event_expr_to_bytecode(
+                               local_capture_desc->event_expression,
+                               &local_capture_desc->bytecode);
+               if (status < 0 || local_capture_desc->bytecode == NULL) {
+                       ret = LTTNG_ERR_INVALID_CAPTURE_EXPRESSION;
+                       goto end;
+               }
+       }
+
+       /* Everything went better than expected */
+       ret = LTTNG_OK;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+const struct lttng_bytecode *
+lttng_condition_event_rule_get_capture_bytecode_at_index(
+               const struct lttng_condition *condition, unsigned int index)
+{
+       const struct lttng_condition_event_rule *event_rule_cond =
+                       container_of(condition,
+                               const struct lttng_condition_event_rule,
+                               parent);
+       struct lttng_capture_descriptor *desc = NULL;
+       struct lttng_bytecode *bytecode = NULL;
+       unsigned int count;
+       enum lttng_condition_status status;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               goto end;
+       }
+
+       status = lttng_condition_event_rule_get_capture_descriptor_count(
+                       condition, &count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       desc = lttng_dynamic_pointer_array_get_pointer(
+                       &event_rule_cond->capture_descriptors, index);
+       if (desc == NULL) {
+               goto end;
+       }
+
+       bytecode = desc->bytecode;
+end:
+       return bytecode;
+}
This page took 0.033575 seconds and 4 git commands to generate.