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
*/
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)
)
)
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"
/* 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
/*
* * 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)
/* 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,
enum ustctl_notify_cmd {
USTCTL_NOTIFY_CMD_EVENT = 0,
USTCTL_NOTIFY_CMD_CHANNEL = 1,
+ USTCTL_NOTIFY_CMD_ENUM = 2,
};
enum ustctl_channel_header {
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;
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.
*/
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;
};
#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];
};
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;
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
/* 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 {
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
}
#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)
#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(...)
#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)
#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)
#undef ctf_string_nowrite
#define ctf_string_nowrite(_item, _src)
+
+#undef ctf_enum_nowrite
+#define ctf_enum_nowrite(_provider, _name, _type, _item, _src)
#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)
#include TRACEPOINT_INCLUDE
+/*
+ * Stage 0.9 of tracepoint event generation
+ *
+ * Unfolding the enums
+ */
+#include <lttng/ust-tracepoint-event-reset.h>
+
+/* 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.
*
.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 */
_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
/*
#include TRACEPOINT_INCLUDE
/*
- * Stage 3 of tracepoint event generation.
+ * Stage 3.0 of tracepoint event generation.
*
* Create static inline function that calculates event size.
*/
#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__
__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__
#include TRACEPOINT_INCLUDE
-
-
/*
* Stage 4 of tracepoint event generation.
*
#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__
__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++]
.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
#include <lttng/ust-abi.h>
#include <lttng/ust-error.h>
#include <lttng/ust-compiler.h>
+#include <lttng/ust-ctl.h>
#include <config.h>
/*
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;
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;
* 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) */
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.
}
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)
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;
}
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:
}
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;
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;
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;
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;
}
}
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)
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++;
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,
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++;
* 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) */
/* 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;
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 */
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);
/* 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 */
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;
}
/*
case 1:
*notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL;
break;
+ case 2:
+ *notify_cmd = USTCTL_NOTIFY_CMD_ENUM;
+ break;
default:
return -EINVAL;
}
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.
*/
}
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);
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;
}
{
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;
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);
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.
*/
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.
*/
/* Fetch event ID from sessiond */
ret = ustcomm_register_event(notify_socket,
+ session,
session->objd,
chan->objd,
event_name,
sessiond_register_error:
free(event);
cache_error:
+create_enum_error:
socket_error:
exist:
return ret;
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;
#include <stdlib.h>
#include <lttng/ust-events.h>
#include <usterr-signal-safe.h>
+#include "jhash.h"
static CDS_LIST_HEAD(lttng_transport_list);
{
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;
+}
-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
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+/*
+ * Copyright (C) 2014 Geneviève Bastien <gbastien@versatic.net>
+ *
+ * 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 <unistd.h>
+
+#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;
+}
--- /dev/null
+/*
+ * tp.c
+ *
+ * Copyright (c) 2014 Geneviève Bastien <gbastien@versatic.net>
+ *
+ * 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"
--- /dev/null
+#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 <gbastien@versatic.net>
+ *
+ * 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 <lttng/tracepoint.h>
+
+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 <lttng/tracepoint-event.h>