X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fconditions%2Fevent-rule.c;h=dcc31ef8622ccdc823d5f85e2ed382d55666fc12;hp=06ba18fa51abbc8c2dbdb6acc167dfbd04d9df93;hb=51dbe9857c314b9b0dc53b4f9c367f7db659a6b4;hpb=683d081a7f3734fcb5c8dd4424b0aa102117d1a0 diff --git a/src/common/conditions/event-rule.c b/src/common/conditions/event-rule.c index 06ba18fa5..dcc31ef86 100644 --- a/src/common/conditions/event-rule.c +++ b/src/common/conditions/event-rule.c @@ -7,12 +7,19 @@ #include #include +#include #include +#include #include +#include #include #include -#include +#include +#include +#include #include +#include +#include #define IS_EVENT_RULE_CONDITION(condition) \ (lttng_condition_get_type(condition) == \ @@ -58,15 +65,177 @@ 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 +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; - 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; + enum lttng_condition_status status; + /* Used for iteration and communication (size matters). */ + uint32_t i, capture_descr_count; if (!condition || !IS_EVENT_RULE_CONDITION(condition)) { ret = -1; @@ -77,28 +246,95 @@ 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); + 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, + 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_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(desc->event_expression, payload); + if (ret) { + goto end; + } + } end: return ret; } +static +bool capture_descriptors_are_equal( + const struct lttng_condition *condition_a, + const struct lttng_condition *condition_b) +{ + bool is_equal = true; + 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; + } + + 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; + } + + for (i = 0; i < capture_descr_count_a; i++) { + const struct lttng_event_expr *expr_a = + lttng_condition_event_rule_get_capture_descriptor_at_index( + condition_a, + i); + const struct lttng_event_expr *expr_b = + lttng_condition_event_rule_get_capture_descriptor_at_index( + condition_b, + 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 +352,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 +371,21 @@ 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_capture_descriptor(void *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( struct lttng_event_rule *rule) { @@ -158,38 +412,186 @@ struct lttng_condition *lttng_condition_event_rule_create( condition->rule = rule; rule = NULL; + lttng_dynamic_pointer_array_init(&condition->capture_descriptors, + destroy_capture_descriptor); + 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 +604,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++) { + enum lttng_condition_status status; + struct lttng_event_expr *expr = event_expr_from_payload( + view, &offset); + + 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 +691,88 @@ 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); + struct lttng_capture_descriptor *descriptor = NULL; + + /* 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; + } + + 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, 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; +} + +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_event_expr *expr = NULL; + const struct lttng_capture_descriptor *desc = NULL; + + desc = lttng_condition_event_rule_get_internal_capture_descriptor_at_index( + condition, index); + if (desc == NULL) { + goto end; + } + expr = desc->event_expression; + +end: + return expr; +} + LTTNG_HIDDEN ssize_t lttng_evaluation_event_rule_create_from_payload( struct lttng_payload_view *view, @@ -417,3 +924,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; +}