} attr;
};
+enum lttng_event_field_type {
+ LTTNG_EVENT_FIELD_OTHER = 0,
+ LTTNG_EVENT_FIELD_INTEGER = 1,
+ LTTNG_EVENT_FIELD_ENUM = 2,
+ LTTNG_EVENT_FIELD_FLOAT = 3,
+ LTTNG_EVENT_FIELD_STRING = 4,
+};
+
+#define LTTNG_EVENT_FIELD_PADDING LTTNG_SYMBOL_NAME_LEN + 32
+struct lttng_event_field {
+ char field_name[LTTNG_SYMBOL_NAME_LEN];
+ enum lttng_event_field_type type;
+ char padding[LTTNG_EVENT_FIELD_PADDING];
+ struct lttng_event event;
+};
+
/*
* Tracer channel attributes. For both kernel and user-space.
*
extern int lttng_list_tracepoints(struct lttng_handle *handle,
struct lttng_event **events);
+/*
+ * List the available tracepoints fields of a specific lttng domain.
+ *
+ * Return the size (number of entries) of the "lttng_event_field" array.
+ * Caller must free(3).
+ */
+extern int lttng_list_tracepoint_fields(struct lttng_handle *handle,
+ struct lttng_event_field **fields);
+
/*
* Check if a session daemon is alive.
*
int ustctl_tracepoint_list_get(int sock, int tp_list_handle,
struct lttng_ust_tracepoint_iter *iter);
+/*
+ * ustctl_tracepoint_field_list returns a tracepoint field list handle,
+ * or negative error value.
+ */
+int ustctl_tracepoint_field_list(int sock);
+
+/*
+ * ustctl_tracepoint_field_list_get is used to iterate on the tp field
+ * list handle. End is iteration is reached when -ENOENT is returned.
+ */
+int ustctl_tracepoint_field_list_get(int sock, int tp_field_list_handle,
+ struct lttng_ust_field_iter *iter);
+
int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v);
int ustctl_wait_quiescent(int sock);
return -ret;
}
+/*
+ * Command LTTNG_LIST_TRACEPOINT_FIELDS processed by the client thread.
+ */
+static ssize_t cmd_list_tracepoint_fields(int domain,
+ struct lttng_event_field **fields)
+{
+ int ret;
+ ssize_t nb_fields = 0;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_UST:
+ nb_fields = ust_app_list_event_fields(fields);
+ if (nb_fields < 0) {
+ ret = LTTCOMM_UST_LIST_FAIL;
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ default: /* fall-through */
+ ret = LTTCOMM_UND;
+ goto error;
+ }
+
+ return nb_fields;
+
+error:
+ /* Return negative value to differentiate return code */
+ return -ret;
+}
+
/*
* Command LTTNG_START_TRACE processed by the client thread.
*/
switch(cmd_ctx->lsm->cmd_type) {
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
+ case LTTNG_LIST_TRACEPOINT_FIELDS:
case LTTNG_LIST_DOMAINS:
case LTTNG_LIST_CHANNELS:
case LTTNG_LIST_EVENTS:
case LTTNG_CALIBRATE:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
+ case LTTNG_LIST_TRACEPOINT_FIELDS:
need_tracing_session = 0;
break;
default:
ret = LTTCOMM_OK;
break;
}
+ case LTTNG_LIST_TRACEPOINT_FIELDS:
+ {
+ struct lttng_event_field *fields;
+ ssize_t nb_fields;
+
+ nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type, &fields);
+ if (nb_fields < 0) {
+ ret = -nb_fields;
+ goto error;
+ }
+
+ /*
+ * Setup lttng message with payload size set to the event list size in
+ * bytes and then copy list into the llm payload.
+ */
+ ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event_field) * nb_fields);
+ if (ret < 0) {
+ free(fields);
+ goto setup_error;
+ }
+
+ /* Copy event list into message payload */
+ memcpy(cmd_ctx->llm->payload, fields,
+ sizeof(struct lttng_event_field) * nb_fields);
+
+ free(fields);
+
+ ret = LTTCOMM_OK;
+ break;
+ }
+
case LTTNG_START_TRACE:
{
ret = cmd_start_trace(cmd_ctx->session);
return ret;
}
+/*
+ * Fill events array with all events name of all registered apps.
+ */
+int ust_app_list_event_fields(struct lttng_event_field **fields)
+{
+ int ret, handle;
+ size_t nbmem, count = 0;
+ struct lttng_ht_iter iter;
+ struct ust_app *app;
+ struct lttng_event_field *tmp;
+
+ nbmem = UST_APP_EVENT_LIST_SIZE;
+ tmp = zmalloc(nbmem * sizeof(struct lttng_event_field));
+ if (tmp == NULL) {
+ PERROR("zmalloc ust app event fields");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ rcu_read_lock();
+
+ cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ struct lttng_ust_field_iter uiter;
+
+ if (!app->compatible) {
+ /*
+ * TODO: In time, we should notice the caller of this error by
+ * telling him that this is a version error.
+ */
+ continue;
+ }
+ handle = ustctl_tracepoint_field_list(app->sock);
+ if (handle < 0) {
+ ERR("UST app list event fields getting handle failed for app pid %d",
+ app->pid);
+ continue;
+ }
+
+ while ((ret = ustctl_tracepoint_field_list_get(app->sock, handle,
+ &uiter)) != -ENOENT) {
+ if (count >= nbmem) {
+ DBG2("Reallocating event field list from %zu to %zu entries", nbmem,
+ 2 * nbmem);
+ nbmem *= 2;
+ tmp = realloc(tmp, nbmem * sizeof(struct lttng_event_field));
+ if (tmp == NULL) {
+ PERROR("realloc ust app event fields");
+ ret = -ENOMEM;
+ goto rcu_error;
+ }
+ }
+
+
+ memcpy(tmp[count].field_name, uiter.field_name, LTTNG_UST_SYM_NAME_LEN);
+ tmp[count].type = uiter.type;
+
+ memcpy(tmp[count].event.name, uiter.event_name, LTTNG_UST_SYM_NAME_LEN);
+ tmp[count].event.loglevel = uiter.loglevel;
+ tmp[count].event.type = LTTNG_UST_TRACEPOINT;
+ tmp[count].event.pid = app->pid;
+ tmp[count].event.enabled = -1;
+ count++;
+ }
+ }
+
+ ret = count;
+ *fields = tmp;
+
+ DBG2("UST app list event fields done (%zu events)", count);
+
+rcu_error:
+ rcu_read_unlock();
+error:
+ return ret;
+}
+
/*
* Free and clean all traceable apps of the global list.
*/
int ust_app_destroy_trace(struct ltt_ust_session *usess, struct ust_app *app);
int ust_app_destroy_trace_all(struct ltt_ust_session *usess);
int ust_app_list_events(struct lttng_event **events);
+int ust_app_list_event_fields(struct lttng_event_field **fields);
int ust_app_create_channel_glb(struct ltt_ust_session *usess,
struct ltt_ust_channel *uchan);
int ust_app_create_event_glb(struct ltt_ust_session *usess,
static int opt_kernel;
static char *opt_channel;
static int opt_domain;
+static int opt_fields;
#if 0
/* Not implemented yet */
static char *opt_cmd_name;
#endif
{"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
{"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
+ {"fields", 'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
{"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
{0, 0, 0, 0, 0, 0, 0}
};
fprintf(ofp, " --list-options Simple listing of options\n");
fprintf(ofp, " -k, --kernel Select kernel domain\n");
fprintf(ofp, " -u, --userspace Select user-space domain.\n");
+ fprintf(ofp, " -f, --fields List event fields.\n");
#if 0
fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
#endif
}
}
+static const char *field_type(struct lttng_event_field *field)
+{
+ switch(field->type) {
+ case LTTNG_EVENT_FIELD_INTEGER:
+ return "integer";
+ case LTTNG_EVENT_FIELD_ENUM:
+ return "enum";
+ case LTTNG_EVENT_FIELD_FLOAT:
+ return "float";
+ case LTTNG_EVENT_FIELD_STRING:
+ return "string";
+ case LTTNG_EVENT_FIELD_OTHER:
+ default: /* fall-through */
+ return "unknown";
+ }
+}
+
+/*
+ * Pretty print single event fields.
+ */
+static void print_event_field(struct lttng_event_field *field)
+{
+ if (!field->field_name[0]) {
+ return;
+ }
+ MSG("%sfield: %s (%s)", indent6, field->field_name,
+ field_type(field));
+}
+
/*
* Ask session daemon for all user space tracepoints available.
*/
return -1;
}
+/*
+ * Ask session daemon for all user space tracepoint fields available.
+ */
+static int list_ust_event_fields(void)
+{
+ int i, size;
+ struct lttng_domain domain;
+ struct lttng_handle *handle;
+ struct lttng_event_field *event_field_list;
+ pid_t cur_pid = 0;
+ struct lttng_event cur_event;
+
+ memset(&domain, 0, sizeof(domain));
+ memset(&cur_event, 0, sizeof(cur_event));
+
+ DBG("Getting UST tracing event fields");
+
+ domain.type = LTTNG_DOMAIN_UST;
+
+ handle = lttng_create_handle(NULL, &domain);
+ if (handle == NULL) {
+ goto error;
+ }
+
+ size = lttng_list_tracepoint_fields(handle, &event_field_list);
+ if (size < 0) {
+ ERR("Unable to list UST event fields");
+ lttng_destroy_handle(handle);
+ return size;
+ }
+
+ MSG("UST events:\n-------------");
+
+ if (size == 0) {
+ MSG("None");
+ }
+
+ for (i = 0; i < size; i++) {
+ if (cur_pid != event_field_list[i].event.pid) {
+ cur_pid = event_field_list[i].event.pid;
+ MSG("\nPID: %d - Name: %s", cur_pid, get_cmdline_by_pid(cur_pid));
+ }
+ if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
+ print_events(&event_field_list[i].event);
+ memcpy(&cur_event, &event_field_list[i].event,
+ sizeof(cur_event));
+ }
+ print_event_field(&event_field_list[i]);
+ }
+
+ MSG("");
+
+ free(event_field_list);
+ lttng_destroy_handle(handle);
+
+ return CMD_SUCCESS;
+
+error:
+ lttng_destroy_handle(handle);
+ return -1;
+}
+
/*
* Ask for all trace events in the kernel and pretty print them.
*/
}
}
if (opt_userspace) {
- ret = list_ust_events();
+ if (opt_fields) {
+ ret = list_ust_event_fields();
+ } else {
+ ret = list_ust_events();
+ }
if (ret < 0) {
goto end;
}
#define MSG(fmt, args...) \
__lttng_print(PRINT_MSG, fmt "\n", ## args)
+#define _MSG(fmt, args...) \
+ __lttng_print(PRINT_MSG, fmt, ## args)
#define ERR(fmt, args...) \
__lttng_print(PRINT_ERR, "Error: " fmt "\n", ## args)
#define WARN(fmt, args...) \
LTTNG_REGISTER_CONSUMER,
LTTNG_START_TRACE,
LTTNG_STOP_TRACE,
+ LTTNG_LIST_TRACEPOINT_FIELDS,
};
/*
return ret / sizeof(struct lttng_event);
}
+/*
+ * Lists all available tracepoint fields of domain.
+ * Sets the contents of the event field array.
+ * Returns the number of lttng_event_field entries in events;
+ * on error, returns a negative value.
+ */
+int lttng_list_tracepoint_fields(struct lttng_handle *handle,
+ struct lttng_event_field **fields)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+
+ if (handle == NULL) {
+ return -1;
+ }
+
+ lsm.cmd_type = LTTNG_LIST_TRACEPOINT_FIELDS;
+ copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ ret = ask_sessiond(&lsm, (void **) fields);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret / sizeof(struct lttng_event_field);
+}
+
/*
* Returns a human readable string describing
* the error code (a negative value).