From: Mathieu Desnoyers Date: Sat, 9 Jan 2016 19:44:30 +0000 (-0500) Subject: Add CTF enum type support to tracepoint event X-Git-Tag: v2.8.0-rc1~48 X-Git-Url: http://git.liburcu.org/?p=lttng-ust.git;a=commitdiff_plain;h=c785c634a51956094130218c2bffeff32756cb69 Add CTF enum type support to tracepoint event Derived from initial implementation by: Geneviève Bastien Bump UST communication protocol version to 6.1 (minor version increase) since we're adding enumeration notification command. Signed-off-by: Mathieu Desnoyers --- diff --git a/configure.ac b/configure.ac index 26bf5a59..c92840bc 100644 --- a/configure.ac +++ b/configure.ac @@ -399,6 +399,7 @@ AC_CONFIG_FILES([ python-lttngust/lttngust/__init__.py tools/Makefile tests/Makefile + tests/ctf-types/Makefile tests/hello/Makefile tests/hello.cxx/Makefile tests/same_line_tracepoint/Makefile diff --git a/doc/man/lttng-ust.3 b/doc/man/lttng-ust.3 index 39849891..0455eea2 100644 --- a/doc/man/lttng-ust.3 +++ b/doc/man/lttng-ust.3 @@ -224,6 +224,17 @@ TRACEPOINT_EVENT( */ ctf_float(float, floatfield, floatarg) ctf_float(double, doublefield, doublearg) + + /* + * ctf_enum: a field using a previously declared + * enumeration args: (provider, enum name, container + * type, field name, argument expression). The + * enumeration itself and its values must have been + * defined previously with the TRACEPOINT_ENUM macro, + * described below. + */ + ctf_enum(sample_component, enumeration_name, int, + enumfield, enumarg) ) ) @@ -231,6 +242,49 @@ There can be an arbitrary number of tracepoint providers within an application, but they must each have their own provider name. Duplicate provider names are not allowed. +The CTF specification also supports enumerations that can be declared +inside a tracepoint provider and used as fields in the tracepoint. This +shows how to specify enumerations and what they can be used for: + +The enumeration is a mapping between an integer, or a range of integers, and a +string. It can be used to have a more compact trace in cases where the possible +values for a field are limited: + +TRACEPOINT_ENUM( + /* + * The provider name, as described in the TRACEPOINT_EVENT macro. + */ + sample_component, + + /* + * The name of this enumeration, that will be used when using this + * global type in tracepoint fields. + */ + enumeration_name, + + /* + * TP_ENUM_VALUES describe the values of this enumeration and what they + * map to. + */ + TP_ENUM_VALUES( + /* + * Maps an integer with this string value. By default, enumerations + * start at 0 and increment 1 for each entry. + */ + ctf_enum_value(string_value) + + /* + * Maps the string value to integers in the range 'start' to 'end' + * inclusively. If 'start' == 'end', then the string is mapped to + * a specific value. + * Enumeration ranges may overlap, but the behavior is + * implementation-defined, each trace reader will handle overlapping + * as it wishes. + */ + ctf_enum_range(start, end, string_value) + ) +) + .fi .SH "ASSIGNING LOGLEVEL TO EVENTS" diff --git a/include/lttng/tracepoint.h b/include/lttng/tracepoint.h index e88db892..16348b86 100644 --- a/include/lttng/tracepoint.h +++ b/include/lttng/tracepoint.h @@ -430,6 +430,50 @@ __tracepoints__ptrs_destroy(void) /* The following declarations must be outside re-inclusion protection. */ +#ifndef TRACEPOINT_ENUM + +/* + * Tracepoint Enumerations + * + * The enumeration is a mapping between an integer, or range of integers, and + * a string. It can be used to have a more compact trace in cases where the + * possible values for a field are limited: + * + * An example: + * + * TRACEPOINT_ENUM(someproject_component, enumname, + * TP_ENUM_VALUES( + * ctf_enum_value("even", 0) + * ctf_enum_value("uneven", 1) + * ctf_enum_range("twoto4", 2, 4) + * ctf_enum_value("five", 5) + * ) + * ) + * + * Where "someproject_component" is the name of the component this enumeration + * belongs to and "enumname" identifies this enumeration. Inside the + * TP_ENUM_VALUES macro is the actual mapping. Each string value can map + * to either a single value with ctf_enum_value or a range of values + * with ctf_enum_range. + * + * Enumeration ranges may overlap, but the behavior is implementation-defined, + * each trace reader will handle overlapping as it wishes. + * + * That enumeration can then be used in a field inside the TP_FIELD macro using + * the following line: + * + * ctf_enum(someproject_component, enumname, enumtype, enumfield, enumval) + * + * Where "someproject_component" and "enumname" match those in the + * TRACEPOINT_ENUM, "enumtype" is a signed or unsigned integer type + * backing the enumeration, "enumfield" is the name of the field and + * "enumval" is the value. + */ + +#define TRACEPOINT_ENUM(provider, name, values) + +#endif /* #ifndef TRACEPOINT_ENUM */ + #ifndef TRACEPOINT_EVENT /* @@ -453,6 +497,9 @@ __tracepoints__ptrs_destroy(void) * * Integer, printed with 0x base 16 * * ctf_integer_hex(unsigned long, field_d, arg1) * + * * Enumeration * + * ctf_enum(someproject_component, enum_name, int, field_e, arg0) + * * * Array Sequence, printed as UTF8-encoded array of bytes * * ctf_array_text(char, field_b, string, FIXED_LEN) * ctf_sequence_text(char, field_c, string, size_t, strlen) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 232a9b90..6ea64c87 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -43,7 +43,7 @@ /* Version for ABI between liblttng-ust, sessiond, consumerd */ #define LTTNG_UST_ABI_MAJOR_VERSION 6 -#define LTTNG_UST_ABI_MINOR_VERSION 0 +#define LTTNG_UST_ABI_MINOR_VERSION 1 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 78e0cf72..7a5f969e 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -255,6 +255,7 @@ enum ustctl_socket_type { enum ustctl_notify_cmd { USTCTL_NOTIFY_CMD_EVENT = 0, USTCTL_NOTIFY_CMD_CHANNEL = 1, + USTCTL_NOTIFY_CMD_ENUM = 2, }; enum ustctl_channel_header { @@ -302,9 +303,21 @@ struct ustctl_float_type { char padding[USTCTL_UST_FLOAT_TYPE_PADDING]; } LTTNG_PACKED; +#define USTCTL_UST_ENUM_ENTRY_PADDING 32 +struct ustctl_enum_entry { + uint64_t start, end; /* start and end are inclusive */ + char string[LTTNG_UST_SYM_NAME_LEN]; + char padding[USTCTL_UST_ENUM_ENTRY_PADDING]; +}; + #define USTCTL_UST_BASIC_TYPE_PADDING 296 union _ustctl_basic_type { struct ustctl_integer_type integer; + struct { + char name[LTTNG_UST_SYM_NAME_LEN]; + struct ustctl_integer_type container_type; + uint64_t id; /* enum ID in sessiond. */ + } enumeration; struct { enum ustctl_string_encodings encoding; } string; @@ -403,6 +416,22 @@ int ustctl_reply_register_event(int sock, uint32_t id, /* event id (input) */ int ret_code); /* return code. 0 ok, negative error */ +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_enum(int sock, + int *session_objd, + char *enum_name, + struct ustctl_enum_entry **entries, + size_t *nr_entries); + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_enum(int sock, + uint64_t id, /* enum id (input) */ + int ret_code); + /* * Returns 0 on success, negative UST or system error value on error. */ diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index b34c9d1b..f7cbc1a6 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -176,7 +176,8 @@ struct lttng_float_type { union _lttng_basic_type { struct lttng_integer_type integer; struct { - const char *name; + const struct lttng_enum_desc *desc; /* Enumeration mapping */ + struct lttng_integer_type container_type; } enumeration; struct { enum lttng_string_encodings encoding; @@ -210,11 +211,10 @@ struct lttng_type { }; #define LTTNG_UST_ENUM_TYPE_PADDING 24 -struct lttng_enum { +struct lttng_enum_desc { const char *name; - struct lttng_type container_type; const struct lttng_enum_entry *entries; - unsigned int len; + unsigned int nr_entries; char padding[LTTNG_UST_ENUM_TYPE_PADDING]; }; @@ -422,6 +422,14 @@ struct lttng_event { int registered; /* has reg'd tracepoint probe */ }; +struct lttng_enum { + const struct lttng_enum_desc *desc; + struct lttng_session *session; + struct cds_list_head node; /* Enum list in session */ + struct cds_hlist_node hlist; /* Session ht of enums */ + uint64_t id; /* Enumeration ID in sessiond */ +}; + struct channel; struct lttng_ust_shm_handle; @@ -506,6 +514,13 @@ struct lttng_ust_event_ht { struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE]; }; +#define LTTNG_UST_ENUM_HT_BITS 12 +#define LTTNG_UST_ENUM_HT_SIZE (1U << LTTNG_UST_ENUM_HT_BITS) + +struct lttng_ust_enum_ht { + struct cds_hlist_head table[LTTNG_UST_ENUM_HT_SIZE]; +}; + /* * IMPORTANT: this structure is part of the ABI between the probe and * UST. Fields need to be only added at the end, never reordered, never @@ -532,6 +547,10 @@ struct lttng_session { /* New UST 2.4 */ int statedump_pending:1; + + /* New UST 2.8 */ + struct lttng_ust_enum_ht enums_ht; /* ht of enumerations */ + struct cds_list_head enums_head; }; struct lttng_transport { @@ -657,6 +676,8 @@ int lttng_session_active(void); typedef int (*t_statedump_func_ptr)(struct lttng_session *session); void lttng_handle_pending_statedump(void *owner); struct cds_list_head *_lttng_get_sessions(void); +struct lttng_enum *lttng_ust_enum_get(struct lttng_session *session, + const char *enum_name); #ifdef __cplusplus } diff --git a/include/lttng/ust-tracepoint-event-nowrite.h b/include/lttng/ust-tracepoint-event-nowrite.h index e87f31e3..8cb142b2 100644 --- a/include/lttng/ust-tracepoint-event-nowrite.h +++ b/include/lttng/ust-tracepoint-event-nowrite.h @@ -54,3 +54,7 @@ #undef ctf_string_nowrite #define ctf_string_nowrite(_item, _src) \ _ctf_string(_item, _src, 1) + +#undef ctf_enum_nowrite +#define ctf_enum_nowrite(_provider, _name, _type, _item, _src) \ + _ctf_enum(_provider, _name, _type, _item, _src, 1) diff --git a/include/lttng/ust-tracepoint-event-reset.h b/include/lttng/ust-tracepoint-event-reset.h index f5981f84..c187061c 100644 --- a/include/lttng/ust-tracepoint-event-reset.h +++ b/include/lttng/ust-tracepoint-event-reset.h @@ -28,6 +28,9 @@ #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) +#undef TRACEPOINT_ENUM +#define TRACEPOINT_ENUM(_provider, _name, _values) + #undef TP_ARGS #define TP_ARGS(...) @@ -61,6 +64,9 @@ #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) + /* "write" */ #undef ctf_integer #define ctf_integer(_type, _item, _src) @@ -92,6 +98,9 @@ #undef ctf_string #define ctf_string(_item, _src) +#undef ctf_enum +#define ctf_enum(_provider, _name, _type, _item, _src) + /* "nowrite" */ #undef ctf_integer_nowrite #define ctf_integer_nowrite(_type, _item, _src) @@ -113,3 +122,6 @@ #undef ctf_string_nowrite #define ctf_string_nowrite(_item, _src) + +#undef ctf_enum_nowrite +#define ctf_enum_nowrite(_provider, _name, _type, _item, _src) diff --git a/include/lttng/ust-tracepoint-event-write.h b/include/lttng/ust-tracepoint-event-write.h index 86c6adc6..444702fc 100644 --- a/include/lttng/ust-tracepoint-event-write.h +++ b/include/lttng/ust-tracepoint-event-write.h @@ -66,3 +66,7 @@ #undef ctf_string #define ctf_string(_item, _src) \ _ctf_string(_item, _src, 0) + +#undef ctf_enum +#define ctf_enum(_provider, _name, _type, _item, _src) \ + _ctf_enum(_provider, _name, _type, _item, _src, 0) diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index d9aa6ce6..aa8b50f8 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -117,6 +117,35 @@ static const char \ #include TRACEPOINT_INCLUDE +/* + * Stage 0.9 of tracepoint event generation + * + * Unfolding the enums + */ +#include + +/* Enumeration entry (single value) */ +#undef ctf_enum_value +#define ctf_enum_value(_string, _value) \ + { _value, _value, _string }, + +/* Enumeration entry (range) */ +#undef ctf_enum_range +#define ctf_enum_range(_string, _range_start, _range_end) \ + { _range_start, _range_end, _string }, + +#undef TP_ENUM_VALUES +#define TP_ENUM_VALUES(...) \ + __VA_ARGS__ + +#undef TRACEPOINT_ENUM +#define TRACEPOINT_ENUM(_provider, _name, _values) \ + const struct lttng_enum_entry __enum_values__##_provider##_##_name[] = { \ + _values \ + }; + +#include TRACEPOINT_INCLUDE + /* * Stage 1 of tracepoint event generation. * @@ -200,6 +229,31 @@ static const char \ .nowrite = _nowrite, \ }, +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ + { \ + .name = #_item, \ + .type = { \ + .atype = atype_enum, \ + .u = { \ + .basic = { \ + .enumeration = { \ + .desc = &__enum_##_provider##_##_name, \ + .container_type = { \ + .size = sizeof(_type) * CHAR_BIT, \ + .alignment = lttng_alignof(_type) * CHAR_BIT, \ + .signedness = lttng_is_signed_type(_type), \ + .reverse_byte_order = 0, \ + .base = 10, \ + .encoding = lttng_encode_none, \ + }, \ + }, \ + }, \ + }, \ + }, \ + .nowrite = _nowrite, \ + }, + #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ /* Only one used in this phase */ @@ -209,6 +263,14 @@ static const char \ _fields \ }; +#undef TRACEPOINT_ENUM +#define TRACEPOINT_ENUM(_provider, _name, _values) \ + static const struct lttng_enum_desc __enum_##_provider##_##_name = { \ + .name = #_provider "_" #_name, \ + .entries = __enum_values__##_provider##_##_name, \ + .nr_entries = _TP_ARRAY_SIZE(__enum_values__##_provider##_##_name), \ + }; + #include TRACEPOINT_INCLUDE /* @@ -230,7 +292,7 @@ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #include TRACEPOINT_INCLUDE /* - * Stage 3 of tracepoint event generation. + * Stage 3.0 of tracepoint event generation. * * Create static inline function that calculates event size. */ @@ -268,6 +330,10 @@ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #define _ctf_string(_item, _src, _nowrite) \ __event_len += __dynamic_len[__dynamic_len_idx++] = strlen(_src) + 1; +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ + _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) + #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ @@ -410,6 +476,10 @@ size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS __stack_data += sizeof(void *); \ } +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ + _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) + #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ @@ -427,8 +497,6 @@ void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\ #include TRACEPOINT_INCLUDE - - /* * Stage 4 of tracepoint event generation. * @@ -460,6 +528,10 @@ void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\ #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ + _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) + #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ @@ -544,6 +616,10 @@ size_t __event_get_align__##_provider##___##_name(_TP_ARGS_PROTO(_args)) \ __chan->ops->event_write(&__ctx, _src, \ __get_dynamic_len(dest)); +#undef _ctf_enum +#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ + _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) + /* Beware: this get len actually consumes the len value */ #undef __get_dynamic_len #define __get_dynamic_len(field) __stackvar.__dynamic_len[__dynamic_len_idx++] @@ -726,7 +802,11 @@ const struct lttng_event_desc __event_desc___##_provider##_##_name = { \ .nr_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_template), \ .loglevel = &__ref_loglevel___##_provider##___##_name, \ .signature = __tp_event_signature___##_provider##___##_template, \ - .u = { .ext = { .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name } }, \ + .u = { \ + .ext = { \ + .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \ + }, \ + }, \ }; #include TRACEPOINT_INCLUDE diff --git a/include/ust-comm.h b/include/ust-comm.h index b9bbb39b..efebbb2a 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -31,6 +31,7 @@ #include #include #include +#include #include /* @@ -50,6 +51,9 @@ struct lttng_event_field; struct lttng_ctx_field; +struct lttng_enum_entry; +struct lttng_integer_type; +struct lttng_session; struct ustctl_reg_msg { uint32_t magic; @@ -147,6 +151,22 @@ struct ustcomm_notify_event_reply { char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; } LTTNG_PACKED; +#define USTCOMM_NOTIFY_ENUM_MSG_PADDING 32 +struct ustcomm_notify_enum_msg { + uint32_t session_objd; + char enum_name[LTTNG_UST_SYM_NAME_LEN]; + uint32_t entries_len; + char padding[USTCOMM_NOTIFY_ENUM_MSG_PADDING]; + /* followed by enum entries */ +} LTTNG_PACKED; + +#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32 +struct ustcomm_notify_enum_reply { + int32_t ret_code; /* 0: ok, negative: error code */ + uint64_t enum_id; + char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; +} LTTNG_PACKED; + #define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING 32 struct ustcomm_notify_channel_msg { uint32_t session_objd; @@ -213,6 +233,7 @@ int ustcomm_send_reg_msg(int sock, * Returns -EPIPE or -ECONNRESET if other end has hung up. */ int ustcomm_register_event(int sock, + struct lttng_session *session, int session_objd, /* session descriptor */ int channel_objd, /* channel descriptor */ const char *event_name, /* event name (input) */ @@ -223,6 +244,17 @@ int ustcomm_register_event(int sock, const char *model_emf_uri, uint32_t *id); /* event id (output) */ +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_enum(int sock, + int session_objd, /* session descriptor */ + const char *enum_name, /* enum name (input) */ + size_t nr_entries, /* entries */ + const struct lttng_enum_entry *entries, + uint64_t *id); /* enum id (output) */ + /* * Returns 0 on success, negative error value on error. * Returns -EPIPE or -ECONNRESET if other end has hung up. diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index d213770f..42c9ddb2 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -697,7 +697,22 @@ int serialize_string_encoding(enum ustctl_string_encodings *ue, } static -int serialize_basic_type(enum ustctl_abstract_types *uatype, +int serialize_integer_type(struct ustctl_integer_type *uit, + const struct lttng_integer_type *lit) +{ + uit->size = lit->size; + uit->signedness = lit->signedness; + uit->reverse_byte_order = lit->reverse_byte_order; + uit->base = lit->base; + if (serialize_string_encoding(&uit->encoding, lit->encoding)) + return -EINVAL; + uit->alignment = lit->alignment; + return 0; +} + +static +int serialize_basic_type(struct lttng_session *session, + enum ustctl_abstract_types *uatype, enum lttng_abstract_types atype, union _ustctl_basic_type *ubt, const union _lttng_basic_type *lbt) @@ -705,18 +720,8 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype, switch (atype) { case atype_integer: { - struct ustctl_integer_type *uit; - const struct lttng_integer_type *lit; - - uit = &ubt->integer; - lit = &lbt->integer; - uit->size = lit->size; - uit->signedness = lit->signedness; - uit->reverse_byte_order = lit->reverse_byte_order; - uit->base = lit->base; - if (serialize_string_encoding(&uit->encoding, lit->encoding)) + if (serialize_integer_type(&ubt->integer, &lbt->integer)) return -EINVAL; - uit->alignment = lit->alignment; *uatype = ustctl_atype_integer; break; } @@ -743,6 +748,27 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype, break; } case atype_enum: + { + strncpy(ubt->enumeration.name, lbt->enumeration.desc->name, + LTTNG_UST_SYM_NAME_LEN); + ubt->enumeration.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + if (serialize_integer_type(&ubt->enumeration.container_type, + &lbt->enumeration.container_type)) + return -EINVAL; + if (session) { + const struct lttng_enum *_enum; + + _enum = lttng_ust_enum_get(session, + lbt->enumeration.desc->name); + if (!_enum) + return -EINVAL; + ubt->enumeration.id = _enum->id; + } else { + ubt->enumeration.id = -1ULL; + } + *uatype = ustctl_atype_enum; + break; + } case atype_array: case atype_sequence: default: @@ -752,7 +778,8 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype, } static -int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) +int serialize_one_type(struct lttng_session *session, + struct ustctl_type *ut, const struct lttng_type *lt) { int ret; @@ -760,7 +787,8 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) case atype_integer: case atype_float: case atype_string: - ret = serialize_basic_type(&ut->atype, lt->atype, + case atype_enum: + ret = serialize_basic_type(session, &ut->atype, lt->atype, &ut->u.basic, <->u.basic); if (ret) return ret; @@ -774,7 +802,7 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) ubt = &ut->u.array.elem_type; lbt = <->u.array.elem_type; ut->u.array.length = lt->u.array.length; - ret = serialize_basic_type(&ubt->atype, lbt->atype, + ret = serialize_basic_type(session, &ubt->atype, lbt->atype, &ubt->u.basic, &lbt->u.basic); if (ret) return -EINVAL; @@ -789,20 +817,19 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) ubt = &ut->u.sequence.length_type; lbt = <->u.sequence.length_type; - ret = serialize_basic_type(&ubt->atype, lbt->atype, + ret = serialize_basic_type(session, &ubt->atype, lbt->atype, &ubt->u.basic, &lbt->u.basic); if (ret) return -EINVAL; ubt = &ut->u.sequence.elem_type; lbt = <->u.sequence.elem_type; - ret = serialize_basic_type(&ubt->atype, lbt->atype, + ret = serialize_basic_type(session, &ubt->atype, lbt->atype, &ubt->u.basic, &lbt->u.basic); if (ret) return -EINVAL; ut->atype = ustctl_atype_sequence; break; } - case atype_enum: default: return -EINVAL; } @@ -810,7 +837,8 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) } static -int serialize_fields(size_t *_nr_write_fields, +int serialize_fields(struct lttng_session *session, + size_t *_nr_write_fields, struct ustctl_field **ustctl_fields, size_t nr_fields, const struct lttng_event_field *lttng_fields) @@ -835,7 +863,7 @@ int serialize_fields(size_t *_nr_write_fields, continue; strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN); f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; - ret = serialize_one_type(&f->type, &lf->type); + ret = serialize_one_type(session, &f->type, &lf->type); if (ret) goto error_type; nr_write_fields++; @@ -850,6 +878,34 @@ error_type: return ret; } +static +int serialize_entries(struct ustctl_enum_entry **_entries, + size_t nr_entries, + const struct lttng_enum_entry *lttng_entries) +{ + struct ustctl_enum_entry *entries; + int i; + + /* Serialize the entries */ + entries = zmalloc(nr_entries * sizeof(*entries)); + if (!entries) + return -ENOMEM; + for (i = 0; i < nr_entries; i++) { + struct ustctl_enum_entry *uentry; + const struct lttng_enum_entry *lentry; + + uentry = &entries[i]; + lentry = <tng_entries[i]; + + uentry->start = lentry->start; + uentry->end = lentry->end; + strncpy(uentry->string, lentry->string, LTTNG_UST_SYM_NAME_LEN); + uentry->string[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + } + *_entries = entries; + return 0; +} + static int serialize_ctx_fields(size_t *_nr_write_fields, struct ustctl_field **ustctl_fields, @@ -876,7 +932,7 @@ int serialize_ctx_fields(size_t *_nr_write_fields, continue; strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN); f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; - ret = serialize_one_type(&f->type, &lf->type); + ret = serialize_one_type(NULL, &f->type, &lf->type); if (ret) goto error_type; nr_write_fields++; @@ -895,6 +951,7 @@ error_type: * Returns 0 on success, negative error value on error. */ int ustcomm_register_event(int sock, + struct lttng_session *session, int session_objd, /* session descriptor */ int channel_objd, /* channel descriptor */ const char *event_name, /* event name (input) */ @@ -931,7 +988,7 @@ int ustcomm_register_event(int sock, /* Calculate fields len, serialize fields. */ if (nr_fields > 0) { - ret = serialize_fields(&nr_write_fields, &fields, + ret = serialize_fields(session, &nr_write_fields, &fields, nr_fields, lttng_fields); if (ret) return ret; @@ -945,14 +1002,15 @@ int ustcomm_register_event(int sock, model_emf_uri_len = 0; } msg.m.model_emf_uri_len = model_emf_uri_len; + len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg)); if (len > 0 && len != sizeof(msg)) { - free(fields); - return -EIO; + ret = -EIO; + goto error_fields; } if (len < 0) { - free(fields); - return len; + ret = len; + goto error_fields; } /* send signature */ @@ -971,10 +1029,12 @@ int ustcomm_register_event(int sock, len = ustcomm_send_unix_sock(sock, fields, fields_len); free(fields); if (len > 0 && len != fields_len) { - return -EIO; + ret = -EIO; + goto error_fields; } if (len < 0) { - return len; + ret = len; + goto error_fields; } } else { free(fields); @@ -984,10 +1044,14 @@ int ustcomm_register_event(int sock, /* send model_emf_uri */ len = ustcomm_send_unix_sock(sock, model_emf_uri, model_emf_uri_len); - if (len > 0 && len != model_emf_uri_len) - return -EIO; - if (len < 0) - return len; + if (len > 0 && len != model_emf_uri_len) { + ret = -EIO; + goto error_fields; + } + if (len < 0) { + ret = len; + goto error_fields; + } } /* receive reply */ @@ -1021,6 +1085,114 @@ int ustcomm_register_event(int sock, return len; } } + +error_fields: + free(fields); + return ret; +} + +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_enum(int sock, + int session_objd, /* session descriptor */ + const char *enum_name, /* enum name (input) */ + size_t nr_entries, /* entries */ + const struct lttng_enum_entry *lttng_entries, + uint64_t *id) +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_enum_msg m; + } msg; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_enum_reply r; + } reply; + size_t entries_len; + struct ustctl_enum_entry *entries = NULL; + int ret; + + memset(&msg, 0, sizeof(msg)); + msg.header.notify_cmd = USTCTL_NOTIFY_CMD_ENUM; + msg.m.session_objd = session_objd; + strncpy(msg.m.enum_name, enum_name, LTTNG_UST_SYM_NAME_LEN); + msg.m.enum_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + + /* Calculate entries len, serialize entries. */ + if (nr_entries > 0) { + ret = serialize_entries(&entries, + nr_entries, lttng_entries); + if (ret) + return ret; + } + + entries_len = sizeof(*entries) * nr_entries; + msg.m.entries_len = entries_len; + + len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) { + ret = -EIO; + goto error_entries; + } + if (len < 0) { + ret = len; + goto error_entries; + } + + /* send entries */ + if (entries_len > 0) { + len = ustcomm_send_unix_sock(sock, entries, entries_len); + if (len > 0 && len != entries_len) { + ret = -EIO; + goto error_entries; + } + if (len < 0) { + ret = len; + goto error_entries; + } + } + free(entries); + entries = NULL; + + /* receive reply */ + len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply)); + switch (len) { + case 0: /* orderly shutdown */ + return -EPIPE; + case sizeof(reply): + if (reply.header.notify_cmd != msg.header.notify_cmd) { + ERR("Unexpected result message command " + "expected: %u vs received: %u\n", + msg.header.notify_cmd, reply.header.notify_cmd); + return -EINVAL; + } + if (reply.r.ret_code > 0) + return -EINVAL; + if (reply.r.ret_code < 0) + return reply.r.ret_code; + *id = reply.r.enum_id; + DBG("Sent register enum notification for name \"%s\": ret_code %d\n", + enum_name, reply.r.ret_code); + return 0; + default: + if (len < 0) { + /* Transport level error */ + if (errno == EPIPE || errno == ECONNRESET) + len = -errno; + return len; + } else { + ERR("incorrect message size: %zd\n", len); + return len; + } + } + return ret; + +error_entries: + free(entries); + return ret; } /* diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 6b6f295b..75b32fe5 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -1759,6 +1759,9 @@ int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd) case 1: *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL; break; + case 2: + *notify_cmd = USTCTL_NOTIFY_CMD_ENUM; + break; default: return -EINVAL; } @@ -1911,6 +1914,90 @@ int ustctl_reply_register_event(int sock, return 0; } +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_enum(int sock, + int *session_objd, + char *enum_name, + struct ustctl_enum_entry **entries, + size_t *nr_entries) +{ + ssize_t len; + struct ustcomm_notify_enum_msg msg; + size_t entries_len; + struct ustctl_enum_entry *a_entries = NULL; + + len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + *session_objd = msg.session_objd; + strncpy(enum_name, msg.enum_name, LTTNG_UST_SYM_NAME_LEN); + enum_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + entries_len = msg.entries_len; + + if (entries_len % sizeof(*a_entries) != 0) { + return -EINVAL; + } + + /* recv entries */ + if (entries_len) { + a_entries = zmalloc(entries_len); + if (!a_entries) + return -ENOMEM; + len = ustcomm_recv_unix_sock(sock, a_entries, entries_len); + if (len > 0 && len != entries_len) { + len = -EIO; + goto entries_error; + } + if (len == 0) { + len = -EPIPE; + goto entries_error; + } + if (len < 0) { + goto entries_error; + } + } + *nr_entries = entries_len / sizeof(*a_entries); + *entries = a_entries; + + return 0; + +entries_error: + free(a_entries); + return len; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_enum(int sock, + uint64_t id, + int ret_code) +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_enum_reply r; + } reply; + + memset(&reply, 0, sizeof(reply)); + reply.header.notify_cmd = USTCTL_NOTIFY_CMD_ENUM; + reply.r.ret_code = ret_code; + reply.r.enum_id = id; + len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); + if (len > 0 && len != sizeof(reply)) + return -EIO; + if (len < 0) + return len; + return 0; +} + /* * Returns 0 on success, negative UST or system error value on error. */ diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 25b49625..eb85b50d 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -72,6 +72,7 @@ struct cds_list_head *_lttng_get_sessions(void) } static void _lttng_event_destroy(struct lttng_event *event); +static void _lttng_enum_destroy(struct lttng_enum *_enum); static void lttng_session_lazy_sync_enablers(struct lttng_session *session); @@ -139,9 +140,12 @@ struct lttng_session *lttng_session_create(void) return NULL; CDS_INIT_LIST_HEAD(&session->chan_head); CDS_INIT_LIST_HEAD(&session->events_head); + CDS_INIT_LIST_HEAD(&session->enums_head); CDS_INIT_LIST_HEAD(&session->enablers_head); for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++) CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]); + for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++) + CDS_INIT_HLIST_HEAD(&session->enums_ht.table[i]); cds_list_add(&session->node, &sessions); return session; } @@ -212,6 +216,7 @@ void lttng_session_destroy(struct lttng_session *session) { struct lttng_channel *chan, *tmpchan; struct lttng_event *event, *tmpevent; + struct lttng_enum *_enum, *tmp_enum; struct lttng_enabler *enabler, *tmpenabler; CMM_ACCESS_ONCE(session->active) = 0; @@ -225,6 +230,9 @@ void lttng_session_destroy(struct lttng_session *session) cds_list_for_each_entry_safe(event, tmpevent, &session->events_head, node) _lttng_event_destroy(event); + cds_list_for_each_entry_safe(_enum, tmp_enum, + &session->enums_head, node) + _lttng_enum_destroy(_enum); cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node) _lttng_channel_unmap(chan); cds_list_del(&session->node); @@ -350,6 +358,101 @@ end: return ret; } +static +int lttng_enum_create(const struct lttng_enum_desc *desc, + struct lttng_session *session) +{ + const char *enum_name = desc->name; + struct lttng_enum *_enum; + struct cds_hlist_head *head; + struct cds_hlist_node *node; + int ret = 0; + size_t name_len = strlen(enum_name); + uint32_t hash; + int notify_socket; + + hash = jhash(enum_name, name_len, 0); + head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)]; + cds_hlist_for_each_entry(_enum, node, head, hlist) { + assert(_enum->desc); + if (!strncmp(_enum->desc->name, desc->name, + LTTNG_UST_SYM_NAME_LEN - 1)) { + ret = -EEXIST; + goto exist; + } + } + + notify_socket = lttng_get_notify_socket(session->owner); + if (notify_socket < 0) { + ret = notify_socket; + goto socket_error; + } + + _enum = zmalloc(sizeof(*_enum)); + if (!_enum) { + ret = -ENOMEM; + goto cache_error; + } + _enum->session = session; + _enum->desc = desc; + + ret = ustcomm_register_enum(notify_socket, + session->objd, + enum_name, + desc->nr_entries, + desc->entries, + &_enum->id); + if (ret < 0) { + DBG("Error (%d) registering enumeration to sessiond", ret); + goto sessiond_register_error; + } + cds_list_add(&_enum->node, &session->enums_head); + cds_hlist_add_head(&_enum->hlist, head); + return 0; + +sessiond_register_error: + free(_enum); +cache_error: +socket_error: +exist: + return ret; +} + +static +int lttng_event_create_all_enums(const struct lttng_event_desc *desc, + struct lttng_session *session) +{ + unsigned int nr_fields, i; + const struct lttng_event_field *fields; + + /* For each field, ensure enum is part of the session. */ + nr_fields = desc->nr_fields; + fields = desc->fields; + for (i = 0; i < nr_fields; i++) { + const struct lttng_type *type = &fields[i].type; + + switch (type->atype) { + case atype_enum: + { + const struct lttng_enum_desc *enum_desc; + int ret; + + enum_desc = type->u.basic.enumeration.desc; + ret = lttng_enum_create(enum_desc, session); + if (ret && ret != -EEXIST) { + DBG("Unable to create enum error: (%d)", ret); + return ret; + } + break; + } + default: + /* TODO: nested types when they become supported. */ + continue; + } + } + return 0; +} + /* * Supports event creation while tracing session is active. */ @@ -386,6 +489,12 @@ int lttng_event_create(const struct lttng_event_desc *desc, goto socket_error; } + ret = lttng_event_create_all_enums(desc, session); + if (ret < 0) { + DBG("Error (%d) adding enum to session", ret); + goto create_enum_error; + } + /* * Check if loglevel match. Refuse to connect event if not. */ @@ -414,6 +523,7 @@ int lttng_event_create(const struct lttng_event_desc *desc, /* Fetch event ID from sessiond */ ret = ustcomm_register_event(notify_socket, + session, session->objd, chan->objd, event_name, @@ -437,6 +547,7 @@ int lttng_event_create(const struct lttng_event_desc *desc, sessiond_register_error: free(event); cache_error: +create_enum_error: socket_error: exist: return ret; @@ -719,6 +830,13 @@ void _lttng_event_destroy(struct lttng_event *event) free(event); } +static +void _lttng_enum_destroy(struct lttng_enum *_enum) +{ + cds_list_del(&_enum->node); + free(_enum); +} + void lttng_ust_events_exit(void) { struct lttng_session *session, *tmpsession; diff --git a/liblttng-ust/ust-core.c b/liblttng-ust/ust-core.c index 60cdbfa9..60751dc3 100644 --- a/liblttng-ust/ust-core.c +++ b/liblttng-ust/ust-core.c @@ -21,6 +21,7 @@ #include #include #include +#include "jhash.h" static CDS_LIST_HEAD(lttng_transport_list); @@ -56,3 +57,26 @@ void lttng_transport_unregister(struct lttng_transport *transport) { cds_list_del(&transport->node); } + +/* + * Needed by comm layer. + */ +struct lttng_enum *lttng_ust_enum_get(struct lttng_session *session, + const char *enum_name) +{ + struct lttng_enum *_enum; + struct cds_hlist_head *head; + struct cds_hlist_node *node; + size_t name_len = strlen(enum_name); + uint32_t hash; + + hash = jhash(enum_name, name_len, 0); + head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)]; + cds_hlist_for_each_entry(_enum, node, head, hlist) { + assert(_enum->desc); + if (!strncmp(_enum->desc->name, enum_name, + LTTNG_UST_SYM_NAME_LEN - 1)) + return _enum; + } + return NULL; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 3d7ceeb9..be300c86 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,5 @@ -SUBDIRS = utils hello same_line_tracepoint snprintf benchmark ust-elf +SUBDIRS = utils hello same_line_tracepoint snprintf benchmark ust-elf \ + ctf-types if CXX_WORKS SUBDIRS += hello.cxx diff --git a/tests/ctf-types/Makefile.am b/tests/ctf-types/Makefile.am new file mode 100644 index 00000000..366870ec --- /dev/null +++ b/tests/ctf-types/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -Wsystem-headers + +noinst_PROGRAMS = ctf-types +ctf_types_SOURCES = ctf-types.c tp.c ust_tests_ctf_types.h +ctf_types_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la +ctf_types_CFLAGS = -Werror=old-style-definition + +if LTTNG_UST_BUILD_WITH_LIBDL +ctf_types_LDADD += -ldl +endif +if LTTNG_UST_BUILD_WITH_LIBC_DL +ctf_types_LDADD += -lc +endif diff --git a/tests/ctf-types/README b/tests/ctf-types/README new file mode 100644 index 00000000..01986531 --- /dev/null +++ b/tests/ctf-types/README @@ -0,0 +1,3 @@ +This is a "hello world" application used to verify that an instrumented program +with tracepoints using type declarations in CTF metadata can be built +successfully. diff --git a/tests/ctf-types/ctf-types.c b/tests/ctf-types/ctf-types.c new file mode 100644 index 00000000..006976a4 --- /dev/null +++ b/tests/ctf-types/ctf-types.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Geneviève Bastien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define TRACEPOINT_DEFINE +#include "ust_tests_ctf_types.h" + +int main(int argc, char **argv) +{ + int i; + int delay = 0; + + if (argc == 2) + delay = atoi(argv[1]); + + fprintf(stderr, "Hello, World!\n"); + + sleep(delay); + + fprintf(stderr, "Tracing... "); + for (i = 0; i < 100; i++) { + tracepoint(ust_tests_ctf_types, tptest, i, i % 6, + i % 21); + } + + for (i = 0; i < 10; i++) { + tracepoint(ust_tests_ctf_types, tptest_bis, i, i % 6); + } + fprintf(stderr, " done.\n"); + return 0; +} diff --git a/tests/ctf-types/tp.c b/tests/ctf-types/tp.c new file mode 100644 index 00000000..6a33fcab --- /dev/null +++ b/tests/ctf-types/tp.c @@ -0,0 +1,26 @@ +/* + * tp.c + * + * Copyright (c) 2014 Geneviève Bastien + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define TRACEPOINT_CREATE_PROBES +#include "ust_tests_ctf_types.h" diff --git a/tests/ctf-types/ust_tests_ctf_types.h b/tests/ctf-types/ust_tests_ctf_types.h new file mode 100644 index 00000000..e789cbe0 --- /dev/null +++ b/tests/ctf-types/ust_tests_ctf_types.h @@ -0,0 +1,83 @@ +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER ust_tests_ctf_types + +#if !defined(_TRACEPOINT_UST_TESTS_CTF_TYPES_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_UST_TESTS_CTF_TYPES_H + +/* + * Copyright (C) 2014 Geneviève Bastien + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +TRACEPOINT_ENUM(ust_tests_ctf_types, testenum, + TP_ENUM_VALUES( + ctf_enum_value("even", 0) + ctf_enum_value("uneven", 1) + ctf_enum_range("twoto4", 2, 4) + ctf_enum_value("five\"extra\\test", 5) + ) +) + +TRACEPOINT_ENUM(ust_tests_ctf_types, testenum2, + TP_ENUM_VALUES( + ctf_enum_value("zero", 0) + ctf_enum_value("five", 5) + ctf_enum_range("ten_to_twenty", 10, 20) + ) +) + +/* + * Enumeration field is used twice to make sure the type declaration + * is entered only once in the metadata file. + */ +TRACEPOINT_EVENT(ust_tests_ctf_types, tptest, + TP_ARGS(int, anint, int, enumval, int, enumval2), + TP_FIELDS( + ctf_integer(int, intfield, anint) + ctf_enum(ust_tests_ctf_types, testenum, int, enumfield, enumval) + ctf_enum(ust_tests_ctf_types, testenum, long long, + enumfield_bis, enumval) + ctf_enum(ust_tests_ctf_types, testenum2, unsigned int, + enumfield_third, enumval2) + ) +) + +/* + * Another tracepoint using the types to make sure each type is entered + * only once in the metadata file. + */ +TRACEPOINT_EVENT(ust_tests_ctf_types, tptest_bis, + TP_ARGS(int, anint, int, enumval), + TP_FIELDS( + ctf_integer(int, intfield, anint) + ctf_enum(ust_tests_ctf_types, testenum, unsigned char, + enumfield, enumval) + ) +) + +#endif /* _TRACEPOINT_UST_TESTS_CTF_TYPES_H */ + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./ust_tests_ctf_types.h" + +/* This part must be outside ifdef protection */ +#include