lttng-ctl: add capture descriptor feature to event rule condition API
[lttng-tools.git] / src / common / conditions / event-rule.c
index 06ba18fa51abbc8c2dbdb6acc167dfbd04d9df93..e7967e6ab2abfb3a924f73706c156bea543fe9f7 100644 (file)
@@ -8,11 +8,15 @@
 #include <assert.h>
 #include <common/error.h>
 #include <common/macros.h>
+#include <inttypes.h>
 #include <lttng/condition/condition-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-rule/event-rule-internal.h>
 #include <stdbool.h>
+#include <stdint.h>
 
 #define IS_EVENT_RULE_CONDITION(condition)      \
        (lttng_condition_get_type(condition) == \
@@ -58,15 +62,143 @@ end:
        return valid;
 }
 
+/*
+ * Serializes the C string `str` into `buf`.
+ *
+ * Encoding is the length of `str` plus one (for the null character),
+ * and then the string, including its null terminator.
+ */
+static
+int serialize_cstr(const char *str, struct lttng_dynamic_buffer *buf)
+{
+       int ret;
+       const uint32_t len = strlen(str) + 1;
+
+       /* Serialize the length, including the null terminator. */
+       DBG("Serializing C string's length (including null terminator): "
+                       "%" PRIu32, len);
+       ret = lttng_dynamic_buffer_append(buf, &len, sizeof(len));
+       if (ret) {
+               goto end;
+       }
+
+       /* Serialize the string. */
+       DBG("Serializing C string: '%s'", str);
+       ret = lttng_dynamic_buffer_append(buf, str, len);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Serializes the event expression `expr` into `buf`.
+ */
+static
+int serialize_event_expr(const struct lttng_event_expr *expr,
+               struct lttng_payload *payload)
+{
+       const uint8_t type = expr->type;
+       int ret;
+
+       /* Serialize the expression's type. */
+       DBG("Serializing event expression's type: %d", expr->type);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &type, sizeof(type));
+       if (ret) {
+               goto end;
+       }
+
+       /* Serialize the expression */
+       switch (expr->type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const struct lttng_event_expr_field *field_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_field,
+                                       parent);
+
+               /* Serialize the field name. */
+               DBG("Serializing field event expression's field name: '%s'",
+                               field_expr->name);
+               ret = serialize_cstr(field_expr->name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const struct lttng_event_expr_app_specific_context_field *field_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_app_specific_context_field,
+                                       parent);
+
+               /* Serialize the provider name. */
+               DBG("Serializing app-specific context field event expression's "
+                               "provider name: '%s'",
+                               field_expr->provider_name);
+               ret = serialize_cstr(field_expr->provider_name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Serialize the type name. */
+               DBG("Serializing app-specific context field event expression's "
+                               "type name: '%s'",
+                               field_expr->provider_name);
+               ret = serialize_cstr(field_expr->type_name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               const struct lttng_event_expr_array_field_element *elem_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_array_field_element,
+                                       parent);
+               const uint32_t index = elem_expr->index;
+
+               /* Serialize the index. */
+               DBG("Serializing array field element event expression's "
+                               "index: %u", elem_expr->index);
+               ret = lttng_dynamic_buffer_append(&payload->buffer, &index, sizeof(index));
+               if (ret) {
+                       goto end;
+               }
+
+               /* Serialize the parent array field expression. */
+               DBG("Serializing array field element event expression's "
+                               "parent array field event expression.");
+               ret = serialize_event_expr(elem_expr->array_field_expr, payload);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
 static int lttng_condition_event_rule_serialize(
                const struct lttng_condition *condition,
                struct lttng_payload *payload)
 {
        int ret;
-       size_t header_offset, size_before_payload;
        struct lttng_condition_event_rule *event_rule;
-       struct lttng_condition_event_rule_comm event_rule_comm = {};
-       struct lttng_condition_event_rule_comm *header = NULL;
+       /* Used for iteration and communication (size matters). */
+       uint32_t i, capture_descr_count;
 
        if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
                ret = -1;
@@ -77,28 +209,82 @@ static int lttng_condition_event_rule_serialize(
        event_rule = container_of(
                        condition, struct lttng_condition_event_rule, parent);
 
-       header_offset = payload->buffer.size;
-       ret = lttng_dynamic_buffer_append(&payload->buffer, &event_rule_comm,
-                       sizeof(event_rule_comm));
+       DBG("Serializing event rule condition's event rule");
+       ret = lttng_event_rule_serialize(event_rule->rule, payload);
        if (ret) {
                goto end;
        }
 
-       size_before_payload = payload->buffer.size;
-       ret = lttng_event_rule_serialize(event_rule->rule, payload);
+       capture_descr_count = lttng_dynamic_pointer_array_get_count(
+                       &event_rule->capture_descriptors);
+       DBG("Serializing event rule condition's capture descriptor count: %" PRIu32,
+                       capture_descr_count);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_descr_count,
+                       sizeof(capture_descr_count));
        if (ret) {
                goto end;
        }
 
-       /* Update payload size. */
-       header = (struct lttng_condition_event_rule_comm *)
-                       ((char *) payload->buffer.data + header_offset);
-       header->event_rule_length = payload->buffer.size - size_before_payload;
+       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);
+
+               DBG("Serializing event rule condition's capture descriptor %" PRIu32,
+                               i);
+               ret = serialize_event_expr(expr, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
 
 end:
        return ret;
 }
 
+static
+bool capture_descriptors_are_equal(
+               const struct lttng_condition_event_rule *condition_a,
+               const struct lttng_condition_event_rule *condition_b)
+{
+       bool is_equal = true;
+       size_t capture_descr_count_a;
+       size_t capture_descr_count_b;
+       size_t i;
+
+       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);
+
+       if (capture_descr_count_a != capture_descr_count_b) {
+               goto not_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,
+                                       i);
+               const struct lttng_event_expr *expr_b =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                       &condition_b->capture_descriptors,
+                                       i);
+
+               if (!lttng_event_expr_is_equal(expr_a, expr_b)) {
+                       goto not_equal;
+               }
+       }
+
+       goto end;
+
+not_equal:
+       is_equal = false;
+
+end:
+       return is_equal;
+}
+
 static bool lttng_condition_event_rule_is_equal(
                const struct lttng_condition *_a,
                const struct lttng_condition *_b)
@@ -116,6 +302,12 @@ static bool lttng_condition_event_rule_is_equal(
        }
 
        is_equal = lttng_event_rule_is_equal(a->rule, b->rule);
+       if (!is_equal) {
+               goto end;
+       }
+
+       is_equal = capture_descriptors_are_equal(a, b);
+
 end:
        return is_equal;
 }
@@ -129,9 +321,16 @@ static void lttng_condition_event_rule_destroy(
                        condition, struct lttng_condition_event_rule, parent);
 
        lttng_event_rule_put(event_rule->rule);
+       lttng_dynamic_pointer_array_reset(&event_rule->capture_descriptors);
        free(event_rule);
 }
 
+static
+void destroy_event_expr(void *ptr)
+{
+       lttng_event_expr_destroy(ptr);
+}
+
 struct lttng_condition *lttng_condition_event_rule_create(
                struct lttng_event_rule *rule)
 {
@@ -158,38 +357,186 @@ struct lttng_condition *lttng_condition_event_rule_create(
        condition->rule = rule;
        rule = NULL;
 
+       lttng_dynamic_pointer_array_init(&condition->capture_descriptors,
+                       destroy_event_expr);
+
        parent = &condition->parent;
 end:
        return parent;
 }
 
+static
+uint64_t uint_from_buffer(const struct lttng_buffer_view *view, size_t size,
+               size_t *offset)
+{
+       uint64_t ret;
+       const struct lttng_buffer_view uint_view =
+                       lttng_buffer_view_from_view(view, *offset, size);
+
+       if (!lttng_buffer_view_is_valid(&uint_view)) {
+               ret = UINT64_C(-1);
+               goto end;
+       }
+
+       switch (size) {
+       case 1:
+               ret = (uint64_t) *uint_view.data;
+               break;
+       case sizeof(uint32_t):
+       {
+               uint32_t u32;
+
+               memcpy(&u32, uint_view.data, sizeof(u32));
+               ret = (uint64_t) u32;
+               break;
+       }
+       case sizeof(ret):
+               memcpy(&ret, uint_view.data, sizeof(ret));
+               break;
+       default:
+               abort();
+       }
+
+       *offset += size;
+
+end:
+       return ret;
+}
+
+static
+const char *str_from_buffer(const struct lttng_buffer_view *view,
+               size_t *offset)
+{
+       uint64_t len;
+       const char *ret;
+
+       len = uint_from_buffer(view, sizeof(uint32_t), offset);
+       if (len == UINT64_C(-1)) {
+               goto error;
+       }
+
+       ret = &view->data[*offset];
+
+       if (!lttng_buffer_view_contains_string(view, ret, len)) {
+               goto error;
+       }
+
+       *offset += len;
+       goto end;
+
+error:
+       ret = NULL;
+
+end:
+       return ret;
+}
+
+static
+struct lttng_event_expr *event_expr_from_payload(
+               struct lttng_payload_view *view, size_t *offset)
+{
+       struct lttng_event_expr *expr = NULL;
+       const char *str;
+       uint64_t type;
+
+       type = uint_from_buffer(&view->buffer, sizeof(uint8_t), offset);
+       if (type == UINT64_C(-1)) {
+               goto error;
+       }
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+               str = str_from_buffer(&view->buffer, offset);
+               if (!str) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_event_payload_field_create(str);
+               break;
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+               str = str_from_buffer(&view->buffer, offset);
+               if (!str) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_channel_context_field_create(str);
+               break;
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name = str_from_buffer(&view->buffer, offset);
+               if (!provider_name) {
+                       goto error;
+               }
+
+               type_name = str_from_buffer(&view->buffer, offset);
+               if (!type_name) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_app_specific_context_field_create(
+                               provider_name, type_name);
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               struct lttng_event_expr *array_field_expr;
+               const uint64_t index = uint_from_buffer(
+                               &view->buffer, sizeof(uint32_t), offset);
+
+               if (index == UINT64_C(-1)) {
+                       goto error;
+               }
+
+               /* Array field expression is the encoded after this. */
+               array_field_expr = event_expr_from_payload(view, offset);
+               if (!array_field_expr) {
+                       goto error;
+               }
+
+               /* Move ownership of `array_field_expr` to new expression. */
+               expr = lttng_event_expr_array_field_element_create(
+                               array_field_expr, (unsigned int) index);
+               if (!expr) {
+                       /* `array_field_expr` not moved: destroy it. */
+                       lttng_event_expr_destroy(array_field_expr);
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       goto end;
+
+error:
+       lttng_event_expr_destroy(expr);
+       expr = NULL;
+
+end:
+       return expr;
+}
+
 LTTNG_HIDDEN
 ssize_t lttng_condition_event_rule_create_from_payload(
                struct lttng_payload_view *view,
                struct lttng_condition **_condition)
 {
-       ssize_t offset, event_rule_length;
+       ssize_t consumed_length;
+       size_t offset = 0;
+       ssize_t event_rule_length;
+       uint32_t i, capture_descr_count;
        struct lttng_condition *condition = NULL;
        struct lttng_event_rule *event_rule = NULL;
-       const struct lttng_condition_event_rule_comm *header;
-       const struct lttng_payload_view header_view =
-                       lttng_payload_view_from_view(
-                                       view, 0, sizeof(*header));
 
        if (!view || !_condition) {
                goto error;
        }
 
-       if (!lttng_payload_view_is_valid(&header_view)) {
-               ERR("Failed to initialize from malformed event rule condition: buffer too short to contain header");
-               goto error;
-       }
-
-       header = (const struct lttng_condition_event_rule_comm *)
-                              header_view.buffer.data;
-       offset = sizeof(*header);
-
-       /* lttng_event_rule payload. */
+       /* Struct lttng_event_rule. */
        {
                struct lttng_payload_view event_rule_view =
                                lttng_payload_view_from_view(view, offset, -1);
@@ -202,30 +549,53 @@ ssize_t lttng_condition_event_rule_create_from_payload(
                goto error;
        }
 
-       if ((size_t) header->event_rule_length != event_rule_length) {
+       /* Create condition (no capture descriptors yet) at this point. */
+       condition = lttng_condition_event_rule_create(event_rule);
+       if (!condition) {
                goto error;
        }
 
-       /* Move to the end of the payload. */
-       offset += header->event_rule_length;
 
-       /* Acquires a reference to the event rule. */
-       condition = lttng_condition_event_rule_create(event_rule);
-       if (!condition) {
+       /* Capture descriptor count. */
+       assert(event_rule_length >= 0);
+       offset += (size_t) event_rule_length;
+       capture_descr_count = uint_from_buffer(&view->buffer, sizeof(uint32_t), &offset);
+       if (capture_descr_count == UINT32_C(-1)) {
                goto error;
        }
 
+       /* Capture descriptors. */
+       for (i = 0; i < capture_descr_count; i++) {
+               struct lttng_event_expr *expr = event_expr_from_payload(
+                               view, &offset);
+               enum lttng_condition_status status;
+
+               if (!expr) {
+                       goto error;
+               }
+
+               /* Move ownership of `expr` to `condition`. */
+               status = lttng_condition_event_rule_append_capture_descriptor(
+                               condition, expr);
+               if (status != LTTNG_CONDITION_STATUS_OK) {
+                       /* `expr` not moved: destroy it. */
+                       lttng_event_expr_destroy(expr);
+                       goto error;
+               }
+       }
+
+       consumed_length = (ssize_t) offset;
        *_condition = condition;
        condition = NULL;
        goto end;
 
 error:
-       offset = -1;
+       consumed_length = -1;
 
 end:
        lttng_event_rule_put(event_rule);
        lttng_condition_put(condition);
-       return offset;
+       return consumed_length;
 }
 
 LTTNG_HIDDEN
@@ -266,6 +636,80 @@ enum lttng_condition_status lttng_condition_event_rule_get_rule(
        return status;
 }
 
+enum lttng_condition_status
+lttng_condition_event_rule_append_capture_descriptor(
+               struct lttng_condition *condition,
+               struct lttng_event_expr *expr)
+{
+       int ret;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+       struct lttng_condition_event_rule *event_rule_cond =
+                       container_of(condition,
+                               struct lttng_condition_event_rule, parent);
+
+       /* Only accept l-values. */
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !expr ||
+                       !lttng_event_expr_is_lvalue(expr)) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &event_rule_cond->capture_descriptors, expr);
+       if (ret) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_event_rule_get_capture_descriptor_count(
+               const struct lttng_condition *condition, unsigned int *count)
+{
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+       const struct lttng_condition_event_rule *event_rule_cond =
+                       container_of(condition,
+                               const struct lttng_condition_event_rule,
+                               parent);
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !count) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(
+                       &event_rule_cond->capture_descriptors);
+
+end:
+       return status;
+}
+
+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;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) ||
+                       index >= lttng_dynamic_pointer_array_get_count(
+                               &event_rule_cond->capture_descriptors)) {
+               goto end;
+       }
+
+       expr = lttng_dynamic_pointer_array_get_pointer(
+                       &event_rule_cond->capture_descriptors, index);
+
+end:
+       return expr;
+}
+
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_event_rule_create_from_payload(
                struct lttng_payload_view *view,
This page took 0.029032 seconds and 4 git commands to generate.