X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fevent.c;h=fd44f6da2133da600197bb0e45353abf09a1cec6;hb=64744f4278ee2c3b0e6c1c45cc420ea9c555969e;hp=0f6ac9a8c1d306a7a3144f139c00461c1792349e;hpb=b583ad836a07eb17b3abebc9354e49a9ce415492;p=lttng-tools.git diff --git a/src/common/event.c b/src/common/event.c index 0f6ac9a8c..fd44f6da2 100644 --- a/src/common/event.c +++ b/src/common/event.c @@ -194,6 +194,7 @@ static ssize_t lttng_event_probe_attr_create_from_buffer( local_attr = NULL; ret = offset; end: + free(local_attr); return ret; } @@ -252,6 +253,7 @@ static ssize_t lttng_event_function_attr_create_from_buffer( local_attr = NULL; ret = offset; end: + free(local_attr); return ret; } @@ -611,7 +613,7 @@ deserialize_event_type_payload: } if (ret != event_comm->userspace_probe_location_len) { - WARN("Userspace probe location from the received buffer is not the advertised length: header length = %" PRIu32 ", payload length = %lu", event_comm->userspace_probe_location_len, ret); + WARN("Userspace probe location from the received buffer is not the advertised length: header length = %" PRIu32 ", payload length = %zd", event_comm->userspace_probe_location_len, ret); ret = -1; goto end; } @@ -1197,7 +1199,8 @@ static int lttng_event_context_app_serialize( } /* Include the null terminator. */ - comm.provider_name_len = provider_len + 1; + provider_len += 1; + comm.provider_name_len = provider_len; ctx_len = strlen(ctx_name); if (ctx_len == 0) { @@ -1206,7 +1209,8 @@ static int lttng_event_context_app_serialize( } /* Include the null terminator. */ - comm.ctx_name_len = ctx_len + 1; + ctx_len += 1; + comm.ctx_name_len = ctx_len; /* Header */ ret = lttng_dynamic_buffer_append(buffer, &comm, sizeof(comm)); @@ -1325,6 +1329,182 @@ void lttng_event_context_destroy(struct lttng_event_context *context) free(context); } + +/* + * This is a specialized populate for lttng_event_field since it ignores + * the extension field of the lttng_event struct and simply copies what it can + * to the internal struct lttng_event of a lttng_event_field. + */ +static void lttng_event_field_populate_lttng_event_from_event( + const struct lttng_event *src, struct lttng_event *destination) +{ + memcpy(destination, src, sizeof(*destination)); + + /* Remove all possible dynamic data from the destination event rule. */ + destination->extended.ptr = NULL; +} + +LTTNG_HIDDEN +ssize_t lttng_event_field_create_from_buffer( + const struct lttng_buffer_view *view, + struct lttng_event_field **field) +{ + ssize_t ret, offset = 0; + struct lttng_event_field *local_event_field = NULL; + struct lttng_event *event = NULL; + const struct lttng_event_field_comm *comm; + const char* name = NULL; + + assert(field); + assert(view); + + { + const struct lttng_buffer_view comm_view = + lttng_buffer_view_from_view( + view, offset, sizeof(*comm)); + + if (!lttng_buffer_view_is_valid(&comm_view)) { + ret = -1; + goto end; + } + /* lttng_event_field_comm header */ + comm = (const struct lttng_event_field_comm *) view->data; + offset += sizeof(*comm); + } + + local_event_field = zmalloc(sizeof(*local_event_field)); + if (!local_event_field) { + ret = -1; + goto end; + } + + local_event_field->type = comm->type; + local_event_field->nowrite = comm->nowrite; + + /* Field name */ + { + const struct lttng_buffer_view name_view = + lttng_buffer_view_from_view( + view, offset, comm->name_len); + + if (!lttng_buffer_view_is_valid(&name_view)) { + ret = -1; + goto end; + } + + name = name_view.data; + + if (!lttng_buffer_view_contains_string(&name_view, name_view.data, comm->name_len)) { + ret = -1; + goto end; + } + + if (comm->name_len > LTTNG_SYMBOL_NAME_LEN - 1) { + /* Name is too long.*/ + ret = -1; + goto end; + } + offset += comm->name_len; + } + + /* Event */ + { + const struct lttng_buffer_view event_view = + lttng_buffer_view_from_view( + view, offset, comm->event_len); + + if (!lttng_buffer_view_is_valid(&event_view)) { + ret = -1; + goto end; + } + ret = lttng_event_create_from_buffer(&event_view, &event, NULL, + NULL, NULL, -1); + if (ret != comm->event_len) { + abort(); + } + offset += ret; + } + + assert(name); + assert(event); + + if (lttng_strncpy(local_event_field->field_name, name , LTTNG_SYMBOL_NAME_LEN)) { + ret = -1; + goto end; + } + + lttng_event_field_populate_lttng_event_from_event( + event, &local_event_field->event); + + *field = local_event_field; + local_event_field = NULL; + ret = offset; +end: + lttng_event_destroy(event); + free(local_event_field); + return ret; +} + +LTTNG_HIDDEN +int lttng_event_field_serialize(const struct lttng_event_field *field, + struct lttng_dynamic_buffer *buffer) +{ + int ret; + size_t header_offset, size_before_event; + size_t name_len; + struct lttng_event_field_comm event_field_comm = { 0 }; + struct lttng_event_field_comm *header; + + assert(field); + assert(buffer); + + /* Save the header location for later in-place header update. */ + header_offset = buffer->size; + + name_len = strnlen(field->field_name, LTTNG_SYMBOL_NAME_LEN); + if (name_len == LTTNG_SYMBOL_NAME_LEN) { + /* Event name is not NULL-terminated. */ + ret = -1; + goto end; + } + + /* Add null termination. */ + name_len += 1; + + event_field_comm.type = field->type; + event_field_comm.nowrite = (uint8_t)field->nowrite; + event_field_comm.name_len = name_len; + + /* Header */ + ret = lttng_dynamic_buffer_append( + buffer, &event_field_comm, sizeof(event_field_comm)); + if (ret) { + goto end; + } + + /* Field name */ + ret = lttng_dynamic_buffer_append(buffer, field->field_name, name_len); + if (ret) { + goto end; + } + + size_before_event = buffer->size; + ret = lttng_event_serialize( + &field->event, 0, NULL, NULL, 0, 0, buffer, NULL); + if (ret) { + ret = -1; + goto end; + } + + /* Update the event len. */ + header = (struct lttng_event_field_comm *) ((char *) buffer->data + + header_offset); + header->event_len = buffer->size - size_before_event; + +end: + return ret; +} + static enum lttng_error_code compute_flattened_size( struct lttng_dynamic_pointer_array *events, size_t *size) { @@ -1640,3 +1820,155 @@ end: lttng_dynamic_pointer_array_reset(&local_events); return ret; } + +static enum lttng_error_code flatten_lttng_event_fields( + struct lttng_dynamic_pointer_array *event_fields, + struct lttng_event_field **flattened_event_fields) +{ + int ret, i; + enum lttng_error_code ret_code; + size_t storage_req = 0; + struct lttng_dynamic_buffer local_flattened_event_fields; + int nb_event_field; + + assert(event_fields); + assert(flattened_event_fields); + + lttng_dynamic_buffer_init(&local_flattened_event_fields); + nb_event_field = lttng_dynamic_pointer_array_get_count(event_fields); + + /* + * Here even if the event field contains a `struct lttng_event` that + * could contain dynamic data, in reality it is not the case. + * Dynamic data is not present. Here the flattening is mostly a direct + * memcpy. This is less than ideal but this code is still better than + * direct usage of an unpacked lttng_event_field array. + */ + storage_req += sizeof(struct lttng_event_field) * nb_event_field; + + lttng_dynamic_buffer_init(&local_flattened_event_fields); + + /* + * We must ensure that "local_flattened_event_fields" is never resized + * so as to preserve the validity of the flattened objects. + */ + ret = lttng_dynamic_buffer_set_capacity( + &local_flattened_event_fields, storage_req); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + for (i = 0; i < nb_event_field; i++) { + const struct lttng_event_field *element = + lttng_dynamic_pointer_array_get_pointer( + event_fields, i); + + if (!element) { + ret_code = LTTNG_ERR_FATAL; + goto end; + } + ret = lttng_dynamic_buffer_append(&local_flattened_event_fields, + element, sizeof(struct lttng_event_field)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + } + + /* Don't reset local_flattened_channels buffer as we return its content. */ + *flattened_event_fields = (struct lttng_event_field *) local_flattened_event_fields.data; + lttng_dynamic_buffer_init(&local_flattened_event_fields); + ret_code = LTTNG_OK; +end: + lttng_dynamic_buffer_reset(&local_flattened_event_fields); + return ret_code; +} + +static enum lttng_error_code event_field_list_create_from_buffer( + const struct lttng_buffer_view *view, + unsigned int count, + struct lttng_dynamic_pointer_array **event_field_list) +{ + enum lttng_error_code ret_code; + int ret, offset = 0; + unsigned int i; + struct lttng_dynamic_pointer_array *list = NULL; + + assert(view); + assert(event_field_list); + + list = zmalloc(sizeof(*list)); + if (!list) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + lttng_dynamic_pointer_array_init(list, free); + + for (i = 0; i < count; i++) { + ssize_t event_field_size; + struct lttng_event_field *field = NULL; + const struct lttng_buffer_view event_field_view = + lttng_buffer_view_from_view(view, offset, -1); + + event_field_size = lttng_event_field_create_from_buffer( + &event_field_view, &field); + if (event_field_size < 0) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + /* Lifetime and management of the object is now bound to the array. */ + ret = lttng_dynamic_pointer_array_add_pointer(list, field); + if (ret) { + free(field); + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + offset += event_field_size; + } + + if (view->size != offset) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + *event_field_list = list; + list = NULL; + ret_code = LTTNG_OK; + +end: + if (list) { + lttng_dynamic_pointer_array_reset(list); + free(list); + } + return ret_code; +} + +LTTNG_HIDDEN +enum lttng_error_code lttng_event_fields_create_and_flatten_from_buffer( + const struct lttng_buffer_view *view, + unsigned int count, + struct lttng_event_field **fields) +{ + enum lttng_error_code ret; + struct lttng_dynamic_pointer_array *local_event_fields = NULL; + + ret = event_field_list_create_from_buffer( + view, count, &local_event_fields); + if (ret != LTTNG_OK) { + goto end; + } + + ret = flatten_lttng_event_fields(local_event_fields, fields); + if (ret != LTTNG_OK) { + goto end; + } +end: + if (local_event_fields) { + lttng_dynamic_pointer_array_reset(local_event_fields); + free(local_event_fields); + } + return ret; +}