X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fevent.cpp;h=f33518eee4eece45c2c8ce762cb22765a682209b;hb=fbc3f258425648821da7264860ca32cc24db0915;hp=8d85a2d7f4ebe9182ac8f077f1ab5d46ec8d6722;hpb=8ddd72efb54e568ddead0aa3fbc05a3ced24da7d;p=lttng-tools.git diff --git a/src/common/event.cpp b/src/common/event.cpp index 8d85a2d7f..f33518eee 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -5,28 +5,28 @@ * */ -#include "common/compat/string.h" -#include "common/macros.h" -#include "lttng/lttng-error.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + #include -#include +#include #include -#include -#include -#include +#include +#include +namespace { struct event_list_element { struct lttng_event *event; struct lttng_event_exclusion *exclusions; char *filter_expression; }; +} /* namespace */ static void event_list_destructor(void *ptr) { @@ -43,7 +43,7 @@ struct lttng_event *lttng_event_copy(const struct lttng_event *event) struct lttng_event *new_event; struct lttng_event_extended *new_event_extended; - new_event = (lttng_event *) zmalloc(sizeof(*event)); + new_event = zmalloc(); if (!new_event) { PERROR("Error allocating event structure"); goto end; @@ -56,7 +56,7 @@ struct lttng_event *lttng_event_copy(const struct lttng_event *event) * We need to create a new extended since the previous pointer is now * invalid. */ - new_event_extended = (lttng_event_extended *) zmalloc(sizeof(*new_event_extended)); + new_event_extended = zmalloc(); if (!new_event_extended) { PERROR("Error allocating event extended structure"); goto error; @@ -77,10 +77,11 @@ static int lttng_event_probe_attr_serialize( { int ret; size_t symbol_name_len; - struct lttng_event_probe_attr_comm comm = { 0 }; + struct lttng_event_probe_attr_comm comm = {}; - symbol_name_len = lttng_strnlen(probe->symbol_name, LTTNG_SYMBOL_NAME_LEN); - if (symbol_name_len == LTTNG_SYMBOL_NAME_LEN) { + symbol_name_len = lttng_strnlen( + probe->symbol_name, sizeof(probe->symbol_name)); + if (symbol_name_len == sizeof(probe->symbol_name)) { /* Not null-termintated. */ ret = -1; goto end; @@ -112,10 +113,13 @@ static int lttng_event_function_attr_serialize( { int ret; size_t symbol_name_len; - struct lttng_event_function_attr_comm comm = { 0 }; + struct lttng_event_function_attr_comm comm; + + comm.symbol_name_len = 0; - symbol_name_len = lttng_strnlen(function->symbol_name, LTTNG_SYMBOL_NAME_LEN); - if (symbol_name_len == LTTNG_SYMBOL_NAME_LEN) { + symbol_name_len = lttng_strnlen( + function->symbol_name, sizeof(function->symbol_name)); + if (symbol_name_len == sizeof(function->symbol_name)) { /* Not null-termintated. */ ret = -1; goto end; @@ -157,8 +161,7 @@ static ssize_t lttng_event_probe_attr_create_from_payload( comm = (typeof(comm)) comm_view.buffer.data; offset += sizeof(*comm); - local_attr = (struct lttng_event_probe_attr *) zmalloc( - sizeof(*local_attr)); + local_attr = zmalloc(); if (local_attr == NULL) { ret = -1; goto end; @@ -187,7 +190,7 @@ static ssize_t lttng_event_probe_attr_create_from_payload( } ret = lttng_strncpy(local_attr->symbol_name, name, - LTTNG_SYMBOL_NAME_LEN); + sizeof(local_attr->symbol_name)); if (ret) { ret = -1; goto end; @@ -200,6 +203,7 @@ static ssize_t lttng_event_probe_attr_create_from_payload( local_attr = NULL; ret = offset; end: + free(local_attr); return ret; } @@ -221,8 +225,7 @@ static ssize_t lttng_event_function_attr_create_from_payload( comm = (typeof(comm)) view->buffer.data; offset += sizeof(*comm); - local_attr = (struct lttng_event_function_attr *) zmalloc( - sizeof(*local_attr)); + local_attr = zmalloc(); if (local_attr == NULL) { ret = -1; goto end; @@ -248,7 +251,7 @@ static ssize_t lttng_event_function_attr_create_from_payload( } ret = lttng_strncpy(local_attr->symbol_name, name, - LTTNG_SYMBOL_NAME_LEN); + sizeof(local_attr->symbol_name)); if (ret) { ret = -1; goto end; @@ -261,6 +264,7 @@ static ssize_t lttng_event_function_attr_create_from_payload( local_attr = NULL; ret = offset; end: + free(local_attr); return ret; } @@ -270,12 +274,12 @@ static ssize_t lttng_event_exclusions_create_from_payload( struct lttng_event_exclusion **exclusions) { ssize_t ret, offset = 0; - size_t size = (count * LTTNG_SYMBOL_NAME_LEN); + const size_t size = (count * LTTNG_SYMBOL_NAME_LEN); uint32_t i; const struct lttng_event_exclusion_comm *comm; struct lttng_event_exclusion *local_exclusions; - local_exclusions = (struct lttng_event_exclusion *) zmalloc( + local_exclusions = zmalloc( sizeof(struct lttng_event_exclusion) + size); if (!local_exclusions) { ret = -1; @@ -315,8 +319,8 @@ static ssize_t lttng_event_exclusions_create_from_payload( goto end; } - ret = lttng_strncpy(local_exclusions->names[i], - string, LTTNG_SYMBOL_NAME_LEN); + ret = lttng_strncpy(LTTNG_EVENT_EXCLUSION_NAME_AT(local_exclusions, i), string, + sizeof(LTTNG_EVENT_EXCLUSION_NAME_AT(local_exclusions, i))); if (ret) { ret = -1; goto end; @@ -404,8 +408,8 @@ ssize_t lttng_event_create_from_payload(struct lttng_payload_view *view, goto end; } - ret = lttng_strncpy( - local_event->name, name, LTTNG_SYMBOL_NAME_LEN); + ret = lttng_strncpy(local_event->name, name, + sizeof(local_event->name)); if (ret) { ret = -1; goto end; @@ -508,8 +512,7 @@ deserialize_filter_expression: goto end; } - local_bytecode = (struct lttng_bytecode *) zmalloc( - event_comm->bytecode_len); + local_bytecode = zmalloc(event_comm->bytecode_len); if (!local_bytecode) { ret = -1; goto end; @@ -619,7 +622,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; } @@ -698,7 +701,7 @@ int lttng_event_serialize(const struct lttng_event *event, unsigned int i; size_t header_offset, size_before_payload; size_t name_len; - struct lttng_event_comm event_comm = { 0 }; + struct lttng_event_comm event_comm = {}; struct lttng_event_comm *header; assert(event); @@ -708,8 +711,8 @@ int lttng_event_serialize(const struct lttng_event *event, /* Save the header location for later in-place header update. */ header_offset = payload->buffer.size; - name_len = lttng_strnlen(event->name, LTTNG_SYMBOL_NAME_LEN); - if (name_len == LTTNG_SYMBOL_NAME_LEN) { + name_len = lttng_strnlen(event->name, sizeof(event->name)); + if (name_len == sizeof(event->name)) { /* Event name is not NULL-terminated. */ ret = -1; goto end; @@ -763,9 +766,9 @@ int lttng_event_serialize(const struct lttng_event *event, for (i = 0; i < exclusion_count; i++) { const size_t exclusion_len = lttng_strnlen( *(exclusion_list + i), LTTNG_SYMBOL_NAME_LEN); - const struct lttng_event_exclusion_comm exclusion_header = { - .len = (uint32_t) exclusion_len + 1, - }; + struct lttng_event_exclusion_comm exclusion_header; + + exclusion_header.len = (uint32_t) exclusion_len + 1; if (exclusion_len == LTTNG_SYMBOL_NAME_LEN) { /* Exclusion is not NULL-terminated. */ @@ -886,6 +889,593 @@ end: return ret; } +static ssize_t lttng_event_context_app_populate_from_payload( + const struct lttng_payload_view *view, + struct lttng_event_context *event_ctx) +{ + ssize_t ret, offset = 0; + const struct lttng_event_context_app_comm *comm; + char *provider_name = NULL, *context_name = NULL; + size_t provider_name_len, context_name_len; + const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view( + &view->buffer, offset, sizeof(*comm)); + + assert(event_ctx->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT); + + if (!lttng_buffer_view_is_valid(&comm_view)) { + ret = -1; + goto end; + } + + comm = (typeof(comm)) comm_view.data; + offset += sizeof(*comm); + + provider_name_len = comm->provider_name_len; + context_name_len = comm->ctx_name_len; + + if (provider_name_len == 0 || context_name_len == 0) { + /* + * Application provider and context names MUST + * be provided. + */ + ret = -1; + goto end; + } + + { + const char *name; + const struct lttng_buffer_view provider_name_view = + lttng_buffer_view_from_view(&view->buffer, + offset, + provider_name_len); + + if (!lttng_buffer_view_is_valid(&provider_name_view)) { + ret = -1; + goto end; + } + + name = provider_name_view.data; + + if (!lttng_buffer_view_contains_string(&provider_name_view, + name, provider_name_len)) { + ret = -1; + goto end; + } + + provider_name = lttng_strndup(name, provider_name_len); + if (!provider_name) { + ret = -1; + goto end; + } + + offset += provider_name_len; + } + + { + const char *name; + const struct lttng_buffer_view context_name_view = + lttng_buffer_view_from_view( + &view->buffer, offset, + context_name_len); + + if (!lttng_buffer_view_is_valid(&context_name_view)) { + ret = -1; + goto end; + } + + name = context_name_view.data; + + if (!lttng_buffer_view_contains_string(&context_name_view, name, + context_name_len)) { + ret = -1; + goto end; + } + + context_name = lttng_strndup(name, context_name_len); + if (!context_name) { + ret = -1; + goto end; + } + + offset += context_name_len; + } + + /* Transfer ownership of the strings */ + event_ctx->u.app_ctx.provider_name = provider_name; + event_ctx->u.app_ctx.ctx_name = context_name; + provider_name = NULL; + context_name = NULL; + + ret = offset; +end: + free(provider_name); + free(context_name); + + return ret; +} + +static ssize_t lttng_event_context_perf_counter_populate_from_payload( + const struct lttng_payload_view *view, + struct lttng_event_context *event_ctx) +{ + int ret; + ssize_t consumed, offset = 0; + const struct lttng_event_context_perf_counter_comm *comm; + size_t name_len; + const struct lttng_buffer_view comm_view = lttng_buffer_view_from_view( + &view->buffer, offset, sizeof(*comm)); + + assert(event_ctx->ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER || + event_ctx->ctx == + LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER || + event_ctx->ctx == LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER); + + if (!lttng_buffer_view_is_valid(&comm_view)) { + consumed = -1; + goto end; + } + + comm = (typeof(comm)) comm_view.data; + offset += sizeof(*comm); + + name_len = comm->name_len; + + { + const char *name; + const struct lttng_buffer_view provider_name_view = + lttng_buffer_view_from_view( + &view->buffer, offset, + name_len); + + if (!lttng_buffer_view_is_valid(&provider_name_view)) { + consumed = -1; + goto end; + } + + name = provider_name_view.data; + + if (!lttng_buffer_view_contains_string( + &provider_name_view, name, name_len)) { + consumed = -1; + goto end; + } + + ret = lttng_strncpy(event_ctx->u.perf_counter.name, name, + sizeof(event_ctx->u.perf_counter.name)); + if (ret) { + consumed = -1; + goto end; + } + offset += name_len; + } + + event_ctx->u.perf_counter.config = comm->config; + event_ctx->u.perf_counter.type = comm->type; + + consumed = offset; + +end: + return consumed; +} + +ssize_t lttng_event_context_create_from_payload( + struct lttng_payload_view *view, + struct lttng_event_context **event_ctx) +{ + ssize_t ret, offset = 0; + const struct lttng_event_context_comm *comm; + struct lttng_event_context *local_context = NULL; + struct lttng_buffer_view comm_view = lttng_buffer_view_from_view( + &view->buffer, offset, sizeof(*comm)); + + assert(event_ctx); + assert(view); + + if (!lttng_buffer_view_is_valid(&comm_view)) { + ret = -1; + goto end; + } + + comm = (typeof(comm)) comm_view.data; + offset += sizeof(*comm); + + local_context = zmalloc(); + if (!local_context) { + ret = -1; + goto end; + } + + local_context->ctx = (lttng_event_context_type) comm->type; + + { + struct lttng_payload_view subtype_view = + lttng_payload_view_from_view(view, offset, -1); + + switch (local_context->ctx) { + case LTTNG_EVENT_CONTEXT_APP_CONTEXT: + ret = lttng_event_context_app_populate_from_payload( + &subtype_view, local_context); + break; + case LTTNG_EVENT_CONTEXT_PERF_COUNTER: + case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER: + case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER: + ret = lttng_event_context_perf_counter_populate_from_payload( + &subtype_view, local_context); + break; + default: + /* Nothing else to deserialize. */ + ret = 0; + break; + } + } + + if (ret < 0) { + goto end; + } + + offset += ret; + + *event_ctx = local_context; + local_context = NULL; + ret = offset; + +end: + free(local_context); + return ret; +} + +static int lttng_event_context_app_serialize( + struct lttng_event_context *context, + struct lttng_payload *payload) +{ + int ret; + struct lttng_event_context_app_comm comm = {}; + size_t provider_len, ctx_len; + const char *provider_name; + const char *ctx_name; + + assert(payload); + assert(context); + assert(context->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT); + + provider_name = context->u.app_ctx.provider_name; + ctx_name = context->u.app_ctx.ctx_name; + + if (!provider_name || !ctx_name) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + provider_len = strlen(provider_name); + if (provider_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + /* Include the null terminator. */ + provider_len += 1; + comm.provider_name_len = provider_len; + + ctx_len = strlen(ctx_name); + if (ctx_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + /* Include the null terminator. */ + ctx_len += 1; + comm.ctx_name_len = ctx_len; + + /* Header */ + ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, + sizeof(comm)); + if (ret) { + ret = -1; + goto end; + } + + ret = lttng_dynamic_buffer_append(&payload->buffer, provider_name, + provider_len); + if (ret) { + ret = -1; + goto end; + } + + ret = lttng_dynamic_buffer_append(&payload->buffer, ctx_name, + ctx_len); + if (ret) { + ret = -1; + goto end; + } + +end: + return ret; +} + +static int lttng_event_context_perf_counter_serialize( + struct lttng_event_perf_counter_ctx *context, + struct lttng_payload *payload) +{ + int ret; + struct lttng_event_context_perf_counter_comm comm = {}; + + assert(payload); + assert(context); + + comm.config = context->config; + comm.type = context->type; + comm.name_len = lttng_strnlen(context->name, sizeof(context->name)); + + if (comm.name_len == sizeof(context->name)) { + ret = -1; + goto end; + } + + /* Include the null terminator. */ + comm.name_len += 1; + + /* Header */ + ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, + sizeof(comm)); + if (ret) { + ret = -1; + goto end; + } + + ret = lttng_dynamic_buffer_append(&payload->buffer, context->name, + comm.name_len); + if (ret) { + ret = -1; + goto end; + } + +end: + return ret; +} + +int lttng_event_context_serialize(struct lttng_event_context *context, + struct lttng_payload *payload) +{ + int ret; + struct lttng_event_context_comm context_comm; + + context_comm.type = 0; + + assert(context); + assert(payload); + + context_comm.type = (uint32_t) context->ctx; + + /* Header */ + ret = lttng_dynamic_buffer_append( + &payload->buffer, &context_comm, sizeof(context_comm)); + if (ret) { + goto end; + } + + switch (context->ctx) { + case LTTNG_EVENT_CONTEXT_APP_CONTEXT: + ret = lttng_event_context_app_serialize(context, payload); + break; + case LTTNG_EVENT_CONTEXT_PERF_COUNTER: + case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER: + case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER: + ret = lttng_event_context_perf_counter_serialize( + &context->u.perf_counter, payload); + break; + default: + /* Nothing else to serialize. */ + break; + } + + if (ret) { + goto end; + } + +end: + return ret; +} + +void lttng_event_context_destroy(struct lttng_event_context *context) +{ + if (!context) { + return; + } + + if (context->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) { + free(context->u.app_ctx.provider_name); + free(context->u.app_ctx.ctx_name); + } + + 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; +} + +ssize_t lttng_event_field_create_from_payload( + struct lttng_payload_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->buffer, offset, + sizeof(*comm)); + + if (!lttng_buffer_view_is_valid(&comm_view)) { + ret = -1; + goto end; + } + + /* lttng_event_field_comm header */ + comm = (const lttng_event_field_comm *) comm_view.data; + offset += sizeof(*comm); + } + + local_event_field = zmalloc(); + if (!local_event_field) { + ret = -1; + goto end; + } + + local_event_field->type = (lttng_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->buffer, 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 */ + { + struct lttng_payload_view event_view = + lttng_payload_view_from_view( + view, offset, + comm->event_len); + + if (!lttng_payload_view_is_valid(&event_view)) { + ret = -1; + goto end; + } + + ret = lttng_event_create_from_payload(&event_view, &event, NULL, + NULL, NULL); + if (ret != comm->event_len) { + ret = -1; + goto end; + } + + offset += ret; + } + + assert(name); + assert(event); + + if (lttng_strncpy(local_event_field->field_name, name, + sizeof(local_event_field->field_name))) { + 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; +} + +int lttng_event_field_serialize(const struct lttng_event_field *field, + struct lttng_payload *payload) +{ + int ret; + size_t header_offset, size_before_event; + size_t name_len; + struct lttng_event_field_comm event_field_comm = {}; + struct lttng_event_field_comm *header; + + assert(field); + assert(payload); + + /* Save the header location for later in-place header update. */ + header_offset = payload->buffer.size; + + name_len = strnlen(field->field_name, sizeof(field->field_name)); + if (name_len == sizeof(field->field_name)) { + /* 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( + &payload->buffer, &event_field_comm, + sizeof(event_field_comm)); + if (ret) { + goto end; + } + + /* Field name */ + ret = lttng_dynamic_buffer_append(&payload->buffer, field->field_name, + name_len); + if (ret) { + goto end; + } + + size_before_event = payload->buffer.size; + ret = lttng_event_serialize( + &field->event, 0, NULL, NULL, 0, 0, payload); + if (ret) { + ret = -1; + goto end; + } + + /* Update the event len. */ + header = (struct lttng_event_field_comm *) + ((char *) payload->buffer.data + + header_offset); + header->event_len = payload->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) { @@ -901,6 +1491,9 @@ static enum lttng_error_code compute_flattened_size( /* The basic struct lttng_event */ storage_req = event_count * sizeof(struct lttng_event); + /* The struct·lttng_event_extended */ + storage_req += event_count * sizeof(struct lttng_event_extended); + for (i = 0; i < event_count; i++) { int probe_storage_req = 0; const struct event_list_element *element = (const struct event_list_element *) @@ -921,10 +1514,6 @@ static enum lttng_error_code compute_flattened_size( probe_storage_req = ret; } - /* The struct·lttng_event_extended */ - storage_req += event_count * - sizeof(struct lttng_event_extended); - if (element->filter_expression) { storage_req += strlen(element->filter_expression) + 1; } @@ -1125,8 +1714,7 @@ static enum lttng_error_code event_list_create_from_payload( ssize_t event_size; struct lttng_payload_view event_view = lttng_payload_view_from_view(view, offset, -1); - struct event_list_element *element = - (struct event_list_element *) zmalloc(sizeof(*element)); + struct event_list_element *element = zmalloc(); if (!element) { ret_code = LTTNG_ERR_NOMEM; @@ -1203,3 +1791,158 @@ 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 = + (const struct lttng_event_field *) + 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_payload( + struct lttng_payload_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(); + 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; + struct lttng_payload_view event_field_view = + lttng_payload_view_from_view(view, offset, -1); + + event_field_size = lttng_event_field_create_from_payload( + &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->buffer.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; +} + +enum lttng_error_code lttng_event_fields_create_and_flatten_from_payload( + struct lttng_payload_view *view, + unsigned int count, + struct lttng_event_field **fields) +{ + enum lttng_error_code ret_code; + struct lttng_dynamic_pointer_array *local_event_fields = NULL; + + ret_code = event_field_list_create_from_payload( + view, count, &local_event_fields); + if (ret_code != LTTNG_OK) { + goto end; + } + + ret_code = flatten_lttng_event_fields(local_event_fields, fields); + if (ret_code != LTTNG_OK) { + goto end; + } +end: + if (local_event_fields) { + lttng_dynamic_pointer_array_reset(local_event_fields); + free(local_event_fields); + } + + return ret_code; +}