From d28fcdec589e6f0c98fed2f6c094defec58e2b24 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 1 May 2020 16:31:01 -0400 Subject: [PATCH] lttng-ctl: add event field value API MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch adds a new read-only event field value API to liblttng-ctl. It also adds the internal functions to create such objects. As of this patch, an event field value is one of: * An unsigned integer (64-bit). * A signed integer (64-bit). * An unsigned enumeration (64-bit). * A signed enumeration (64-bit). * A real number (double precision). * A string (UTF-8). * An array of zero or more event field values. The first purpose of this API will be to access the captured field values of a notification's trigger condition evaluation. An enumeration event field value conceptually is an integer event field value, therefore lttng_event_field_value_unsigned_int_get_value() works for an unsigned enumeration and lttng_event_field_value_signed_int_get_value() works for a signed enumeration. The compound event field values (array only, as of this patch) can return the `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status when you access a contained event field value. This indicates that there is no field at this location. For the captured field value use case, it means the event did not have any field at that position considering the condition's capture descriptors. Internally, call lttng_event_field_value_array_append_unavailable() to append an unavailable event field value to an array field value. The lttng_event_field_value_array_get_element_at_index() function can also return an event field value of which the type, as returned by lttng_event_field_value_get_type(), is `LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN`. This is different from the `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status: the event field value exists (which is why there's a valid `struct lttng_event_field_value *`), but its type is unknown by this version of the library. This makes it possible to add new event field value types in the future while remaining forward compatible. Note that enumeration labels will not visible to clients since the kernel tracer does not make their content accessible to the session daemon. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau Change-Id: I04d327d9f50ff6c6e2ad1f5a1e56c3af25c92c15 Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479 --- include/Makefile.am | 2 + include/lttng/event-field-value-internal.h | 190 +++++++ include/lttng/event-field-value.h | 229 ++++++++ include/lttng/lttng.h | 1 + src/common/Makefile.am | 1 + src/common/event-field-value.c | 592 +++++++++++++++++++++ 6 files changed, 1015 insertions(+) create mode 100644 include/lttng/event-field-value-internal.h create mode 100644 include/lttng/event-field-value.h create mode 100644 src/common/event-field-value.c diff --git a/include/Makefile.am b/include/Makefile.am index 54fec49a2..b75602b27 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -104,6 +104,7 @@ lttnginclude_HEADERS = \ lttng/domain.h \ lttng/event.h \ lttng/event-expr.h \ + lttng/event-field-value.h \ lttng/handle.h \ lttng/session.h \ lttng/lttng-error.h \ @@ -178,6 +179,7 @@ noinst_HEADERS = \ lttng/domain-internal.h \ lttng/event-internal.h \ lttng/event-expr-internal.h \ + lttng/event-field-value-internal.h \ lttng/rotate-internal.h \ lttng/ref-internal.h \ lttng/location-internal.h \ diff --git a/include/lttng/event-field-value-internal.h b/include/lttng/event-field-value-internal.h new file mode 100644 index 000000000..e0b67e94d --- /dev/null +++ b/include/lttng/event-field-value-internal.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2020 Philippe Proulx + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_EVENT_FIELD_VALUE_INTERNAL_H +#define LTTNG_EVENT_FIELD_VALUE_INTERNAL_H + +#include +#include +#include +#include + +struct lttng_event_field_value { + enum lttng_event_field_value_type type; +}; + +/* + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT`. + */ +struct lttng_event_field_value_uint { + struct lttng_event_field_value parent; + uint64_t val; +}; + +/* + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT`. + */ +struct lttng_event_field_value_int { + struct lttng_event_field_value parent; + int64_t val; +}; + +/* + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` and + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM` (base). + */ +struct lttng_event_field_value_enum { + struct lttng_event_field_value parent; + + /* + * Array of `char *` (owned by this). + */ + struct lttng_dynamic_pointer_array labels; +}; + +/* + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM`. + */ +struct lttng_event_field_value_enum_uint { + struct lttng_event_field_value_enum parent; + uint64_t val; +}; + +/* + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`. + */ +struct lttng_event_field_value_enum_int { + struct lttng_event_field_value_enum parent; + int64_t val; +}; + +/* `LTTNG_EVENT_FIELD_VALUE_TYPE_REAL` */ +struct lttng_event_field_value_real { + struct lttng_event_field_value parent; + double val; +}; + +/* `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING` */ +struct lttng_event_field_value_string { + struct lttng_event_field_value parent; + + /* Owned by this */ + char *val; +}; + +/* `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING` */ +struct lttng_event_field_value_array { + struct lttng_event_field_value parent; + + /* + * Array of `struct lttng_event_field_value *` (owned by this). + * + * A `NULL` element means it's unavailable + * (`LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status). + */ + struct lttng_dynamic_pointer_array elems; +}; + +/* + * This is internal since the session daemon knows nothing about the + * enumeration fields produced by the kernel tracer. Indeed, the kernel tracer + * manages its own metadata which remains opaque to the rest of the toolchain. + * + * Enumerations could be supported for the user space tracer, but it is not the + * case right now. + */ + +/* + * Sets `*count` to the number of labels of the enumeration event field + * value `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` or + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`. + * * `count` is `NULL`. + */ +LTTNG_HIDDEN +enum lttng_event_field_value_status +lttng_event_field_value_enum_get_label_count( + const struct lttng_event_field_value *field_val, + unsigned int *count); + +/* + * Returns the label at index `index` of the enumeration event field + * value `field_val`, or `NULL` if: + * + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` or + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`. + * * `index` is greater than or equal to the label count of `field_val`, + * as returned by lttng_event_field_value_enum_get_label_count(). + */ +LTTNG_HIDDEN +const char *lttng_event_field_value_enum_get_label_at_index( + const struct lttng_event_field_value *field_val, + unsigned int index); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_uint_create( + uint64_t val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_int_create( + int64_t val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_enum_uint_create( + uint64_t val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_enum_int_create( + int64_t val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_real_create(double val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_string_create( + const char *val); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_string_create_with_size( + const char *val, size_t size); + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_array_create(void); + +LTTNG_HIDDEN +int lttng_event_field_value_enum_append_label( + struct lttng_event_field_value *field_val, const char *label); + +LTTNG_HIDDEN +int lttng_event_field_value_enum_append_label_with_size( + struct lttng_event_field_value *field_val, const char *label, + size_t size); + +LTTNG_HIDDEN +int lttng_event_field_value_array_append( + struct lttng_event_field_value *array_field_val, + struct lttng_event_field_value *field_val); + +LTTNG_HIDDEN +int lttng_event_field_value_array_append_unavailable( + struct lttng_event_field_value *array_field_val); + +LTTNG_HIDDEN +void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val); + +#endif /* LTTNG_EVENT_FIELD_VALUE_INTERNAL_H */ diff --git a/include/lttng/event-field-value.h b/include/lttng/event-field-value.h new file mode 100644 index 000000000..db4a4fb3b --- /dev/null +++ b/include/lttng/event-field-value.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2020 Philippe Proulx + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_EVENT_FIELD_VALUE_H +#define LTTNG_EVENT_FIELD_VALUE_H + +#include + +struct lttng_event_field_value; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Types of a event field value expression. + */ +enum lttng_event_field_value_type { + /* + * Unknown. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN = -2, + + /* + * Returned by lttng_event_field_value_get_type() with an + * invalid parameter. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID = -1, + + /* + * Unsigned integer event field value. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT = 0, + + /* + * Signed integer event field value. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT = 1, + + /* + * Unsigned enumeration event field value. + * + * This type conceptually inherits + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT`. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM = 2, + + /* + * Signed enumeration event field value. + * + * This type conceptually inherits + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT`. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM = 3, + + /* + * Real event field value. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_REAL = 4, + + /* + * String event field value. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_STRING = 5, + + /* + * Array event field value. + */ + LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY = 6, +}; + +/* + * Event field value API status codes. + */ +enum lttng_event_field_value_status { + /* + * Event field value is not available. + */ + LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE = -2, + + /* + * Invalid parameter. + */ + LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID = -1, + + /* + * Success. + */ + LTTNG_EVENT_FIELD_VALUE_STATUS_OK = 0, +}; + +/* + * Returns the type of the event field value `field_val`, or: + * + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN`: + * The type of `field_val` is unknown as of this version of the + * LTTng control library. + * + * `LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID`: + * `field_val` is `NULL`. + */ +extern enum lttng_event_field_value_type lttng_event_field_value_get_type( + const struct lttng_event_field_value *field_val); + +/* + * Sets `*val` to the raw value of the unsigned integer/enumeration + * event field value `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT` or + * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM`. + * * `val` is `NULL`. + */ +extern enum lttng_event_field_value_status +lttng_event_field_value_unsigned_int_get_value( + const struct lttng_event_field_value *field_val, uint64_t *val); + +/* + * Sets `*val` to the raw value of the signed integer/enumeration event + * field value `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT` or + * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`. + * * `val` is `NULL`. + */ +extern enum lttng_event_field_value_status +lttng_event_field_value_signed_int_get_value( + const struct lttng_event_field_value *field_val, int64_t *val); + +/* + * Sets `*val` to the raw value of the real event field value + * `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_REAL`. + * * `val` is `NULL`. + */ +extern enum lttng_event_field_value_status +lttng_event_field_value_real_get_value( + const struct lttng_event_field_value *field_val, double *val); + +/* + * Returns the raw value (an UTF-8 C string) of the string event field + * value `field_val`, or `NULL` if: + * + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING`. + */ +extern const char *lttng_event_field_value_string_get_value( + const struct lttng_event_field_value *field_val); + +/* + * Sets `*length` to the length (the number of contained elements) of + * the array event field value `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY`. + * * `length` is `NULL`. + */ +extern enum lttng_event_field_value_status +lttng_event_field_value_array_get_length( + const struct lttng_event_field_value *field_val, + unsigned int *length); + +/* + * Sets `*elem_field_val` to the event field value at index `index` in + * the array event field value `field_val`. + * + * Returns: + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`: + * Success. + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`: + * * `field_val` is `NULL`. + * * The type of `field_val` is not + * `LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY`. + * * `index` is greater than or equal to the length of `field_val`, + * as returned by lttng_event_field_value_array_get_length(). + * + * `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE`: + * * No event field value exists at index `index` within + * `field_val`. + */ +extern enum lttng_event_field_value_status +lttng_event_field_value_array_get_element_at_index( + const struct lttng_event_field_value *field_val, + unsigned int index, + const struct lttng_event_field_value **elem_field_val); + +#ifdef __cplusplus +} +#endif + +#endif /* LTTNG_EVENT_FIELD_VALUE_H */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 2b8a56e37..c665d3c9b 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/src/common/Makefile.am b/src/common/Makefile.am index c7220f703..4b549aa08 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -60,6 +60,7 @@ libcommon_la_SOURCES = \ evaluation.c \ event.c \ event-expr-to-bytecode.c event-expr-to-bytecode.h \ + event-field-value.c \ event-rule/event-rule.c \ event-rule/kprobe.c \ event-rule/syscall.c \ diff --git a/src/common/event-field-value.c b/src/common/event-field-value.c new file mode 100644 index 000000000..d7687880f --- /dev/null +++ b/src/common/event-field-value.c @@ -0,0 +1,592 @@ +/* + * event-field-value.c + * + * Linux Trace Toolkit Control Library + * + * Copyright (C) 2020 Philippe Proulx + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#define _LGPL_SOURCE +#include +#include +#include + +#include +#include +#include + +static +struct lttng_event_field_value *create_empty_field_val( + enum lttng_event_field_value_type type, size_t size) +{ + struct lttng_event_field_value *field_val; + + field_val = zmalloc(size); + if (!field_val) { + goto end; + } + + field_val->type = type; + +end: + return field_val; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_uint_create( + uint64_t val) +{ + struct lttng_event_field_value_uint *field_val; + + field_val = container_of(create_empty_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT, + sizeof(*field_val)), + struct lttng_event_field_value_uint, parent); + if (!field_val) { + goto error; + } + + field_val->val = val; + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return &field_val->parent; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_int_create( + int64_t val) +{ + struct lttng_event_field_value_int *field_val; + + field_val = container_of(create_empty_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT, + sizeof(*field_val)), + struct lttng_event_field_value_int, parent); + if (!field_val) { + goto error; + } + + field_val->val = val; + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return &field_val->parent; +} + +static +struct lttng_event_field_value_enum *create_enum_field_val( + enum lttng_event_field_value_type type, size_t size) +{ + struct lttng_event_field_value_enum *field_val; + + field_val = container_of(create_empty_field_val(type, size), + struct lttng_event_field_value_enum, parent); + if (!field_val) { + goto error; + } + + lttng_dynamic_pointer_array_init(&field_val->labels, free); + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return field_val; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_enum_uint_create( + uint64_t val) +{ + struct lttng_event_field_value_enum_uint *field_val; + + field_val = container_of(create_enum_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM, + sizeof(*field_val)), + struct lttng_event_field_value_enum_uint, parent); + if (!field_val) { + goto error; + } + + field_val->val = val; + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent.parent); + +end: + return &field_val->parent.parent; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_enum_int_create( + int64_t val) +{ + struct lttng_event_field_value_enum_int *field_val; + + field_val = container_of(create_enum_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM, + sizeof(*field_val)), + struct lttng_event_field_value_enum_int, parent); + if (!field_val) { + goto error; + } + + field_val->val = val; + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent.parent); + +end: + return &field_val->parent.parent; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_real_create(double val) +{ + struct lttng_event_field_value_real *field_val = container_of( + create_empty_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_REAL, + sizeof(*field_val)), + struct lttng_event_field_value_real, parent); + + if (!field_val) { + goto error; + } + + field_val->val = val; + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return &field_val->parent; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_string_create_with_size( + const char *val, size_t size) +{ + struct lttng_event_field_value_string *field_val = container_of( + create_empty_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_STRING, + sizeof(*field_val)), + struct lttng_event_field_value_string, parent); + + if (!field_val) { + goto error; + } + + assert(val); + field_val->val = strndup(val, size); + if (!field_val->val) { + goto error; + } + + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return &field_val->parent; +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_string_create( + const char *val) +{ + assert(val); + return lttng_event_field_value_string_create_with_size(val, + strlen(val)); +} + +static +void destroy_field_val(void *field_val) +{ + lttng_event_field_value_destroy(field_val); +} + +LTTNG_HIDDEN +struct lttng_event_field_value *lttng_event_field_value_array_create(void) +{ + struct lttng_event_field_value_array *field_val = container_of( + create_empty_field_val( + LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY, + sizeof(*field_val)), + struct lttng_event_field_value_array, parent); + + if (!field_val) { + goto error; + } + + lttng_dynamic_pointer_array_init(&field_val->elems, destroy_field_val); + goto end; + +error: + lttng_event_field_value_destroy(&field_val->parent); + +end: + return &field_val->parent; +} + +LTTNG_HIDDEN +void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val) +{ + if (!field_val) { + goto end; + } + + switch (field_val->type) { + case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM: + case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM: + { + struct lttng_event_field_value_enum *enum_field_val = + container_of(field_val, + struct lttng_event_field_value_enum, parent); + + lttng_dynamic_pointer_array_reset(&enum_field_val->labels); + break; + } + case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING: + { + struct lttng_event_field_value_string *str_field_val = + container_of(field_val, + struct lttng_event_field_value_string, parent); + + free(str_field_val->val); + break; + } + case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY: + { + struct lttng_event_field_value_array *array_field_expr = + container_of(field_val, + struct lttng_event_field_value_array, + parent); + + lttng_dynamic_pointer_array_reset(&array_field_expr->elems); + break; + } + default: + break; + } + + free(field_val); + +end: + return; +} + +LTTNG_HIDDEN +int lttng_event_field_value_enum_append_label_with_size( + struct lttng_event_field_value *field_val, + const char *label, size_t size) +{ + int ret; + char *new_label; + + assert(field_val); + assert(label); + new_label = strndup(label, size); + if (!new_label) { + ret = -1; + goto end; + } + + ret = lttng_dynamic_pointer_array_add_pointer( + &container_of(field_val, + struct lttng_event_field_value_enum, parent)->labels, + new_label); + if (ret == 0) { + new_label = NULL; + } + +end: + free(new_label); + return ret; +} + +LTTNG_HIDDEN +int lttng_event_field_value_enum_append_label( + struct lttng_event_field_value *field_val, + const char *label) +{ + assert(label); + return lttng_event_field_value_enum_append_label_with_size(field_val, + label, strlen(label)); +} + +LTTNG_HIDDEN +int lttng_event_field_value_array_append( + struct lttng_event_field_value *array_field_val, + struct lttng_event_field_value *field_val) +{ + assert(array_field_val); + assert(field_val); + return lttng_dynamic_pointer_array_add_pointer( + &container_of(array_field_val, + struct lttng_event_field_value_array, parent)->elems, + field_val); +} + +LTTNG_HIDDEN +int lttng_event_field_value_array_append_unavailable( + struct lttng_event_field_value *array_field_val) +{ + assert(array_field_val); + return lttng_dynamic_pointer_array_add_pointer( + &container_of(array_field_val, + struct lttng_event_field_value_array, parent)->elems, + NULL); +} + +enum lttng_event_field_value_type lttng_event_field_value_get_type( + const struct lttng_event_field_value *field_val) +{ + enum lttng_event_field_value_type type; + + if (!field_val) { + type = LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID; + goto end; + } + + type = field_val->type; + +end: + return type; +} + +enum lttng_event_field_value_status +lttng_event_field_value_unsigned_int_get_value( + const struct lttng_event_field_value *field_val, uint64_t *val) +{ + enum lttng_event_field_value_status status; + + if (!field_val || !val) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + switch (field_val->type) { + case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT: + *val = container_of(field_val, + const struct lttng_event_field_value_uint, + parent)->val; + break; + case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM: + *val = container_of( + container_of(field_val, + const struct lttng_event_field_value_enum, + parent), + const struct lttng_event_field_value_enum_uint, + parent)->val; + break; + default: + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + +end: + return status; +} + +enum lttng_event_field_value_status +lttng_event_field_value_signed_int_get_value( + const struct lttng_event_field_value *field_val, int64_t *val) +{ + enum lttng_event_field_value_status status; + + if (!field_val || !val) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + switch (field_val->type) { + case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT: + *val = container_of(field_val, + const struct lttng_event_field_value_int, + parent)->val; + break; + case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM: + *val = container_of( + container_of(field_val, + const struct lttng_event_field_value_enum, + parent), + const struct lttng_event_field_value_enum_int, + parent)->val; + break; + default: + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + +end: + return status; +} + +enum lttng_event_field_value_status +lttng_event_field_value_real_get_value( + const struct lttng_event_field_value *field_val, double *val) +{ + enum lttng_event_field_value_status status; + + if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_REAL || + !val) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + *val = container_of(field_val, + const struct lttng_event_field_value_real, parent)->val; + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + +end: + return status; +} + +static +bool is_enum_field_val(const struct lttng_event_field_value *field_val) +{ + return field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM || + field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM; +} + +enum lttng_event_field_value_status +lttng_event_field_value_enum_get_label_count( + const struct lttng_event_field_value *field_val, + unsigned int *count) +{ + enum lttng_event_field_value_status status; + + if (!field_val || !is_enum_field_val(field_val) || !count) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + *count = (unsigned int) lttng_dynamic_pointer_array_get_count( + &container_of(field_val, + const struct lttng_event_field_value_enum, + parent)->labels); + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + +end: + return status; +} + +const char *lttng_event_field_value_enum_get_label_at_index( + const struct lttng_event_field_value *field_val, + unsigned int index) +{ + const char *ret; + const struct lttng_event_field_value_enum *enum_field_val; + + if (!field_val || !is_enum_field_val(field_val)) { + ret = NULL; + goto end; + } + + enum_field_val = container_of(field_val, + const struct lttng_event_field_value_enum, parent); + + if (index >= lttng_dynamic_pointer_array_get_count(&enum_field_val->labels)) { + ret = NULL; + goto end; + } + + ret = lttng_dynamic_pointer_array_get_pointer(&enum_field_val->labels, + index); + +end: + return ret; +} + +const char *lttng_event_field_value_string_get_value( + const struct lttng_event_field_value *field_val) +{ + const char *ret; + + if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_STRING) { + ret = NULL; + goto end; + } + + ret = container_of(field_val, + const struct lttng_event_field_value_string, parent)->val; + +end: + return ret; +} + +enum lttng_event_field_value_status lttng_event_field_value_array_get_length( + const struct lttng_event_field_value *field_val, + unsigned int *length) +{ + enum lttng_event_field_value_status status; + + if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY || + !length) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + *length = (unsigned int) lttng_dynamic_pointer_array_get_count( + &container_of(field_val, + const struct lttng_event_field_value_array, + parent)->elems); + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + +end: + return status; +} + +enum lttng_event_field_value_status +lttng_event_field_value_array_get_element_at_index( + const struct lttng_event_field_value *field_val, + unsigned int index, + const struct lttng_event_field_value **elem_field_val) +{ + enum lttng_event_field_value_status status; + const struct lttng_event_field_value_array *array_field_val; + + if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY || + !elem_field_val) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + array_field_val = container_of(field_val, + const struct lttng_event_field_value_array, parent); + + if (index >= lttng_dynamic_pointer_array_get_count(&array_field_val->elems)) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; + goto end; + } + + *elem_field_val = lttng_dynamic_pointer_array_get_pointer( + &array_field_val->elems, index); + if (*elem_field_val) { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; + } else { + status = LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE; + } + +end: + return status; +} -- 2.34.1