From 9f19cc17a942a7089fc209a2527d8b2960c83a00 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 3 Aug 2011 15:56:54 -0400 Subject: [PATCH] Improve the lttng list feature Introduce three new functions to the public API which are lttng_list_channels, lttng_list_events and lttng_list_domains. Also add the lttng_list_kernel_events which list available tracing events of the kernel. Adds new options to the lttng list command for listing a lot more details of a tracing session including channels, events and domains. Also adds the enabled flag to the lttng_event and lttng_channel structure. Fix a bad pointer cast in list events. Signed-off-by: David Goulet --- include/lttng/lttng.h | 57 +++- liblttngctl/liblttngctl.c | 100 +++++- liblttsessiondcomm/liblttsessiondcomm.h | 12 +- ltt-sessiond/kernel-ctl.c | 38 ++- ltt-sessiond/kernel-ctl.h | 2 +- ltt-sessiond/main.c | 205 ++++++++---- lttng/commands/list.c | 406 +++++++++++++++++------- 7 files changed, 597 insertions(+), 223 deletions(-) diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 2cbb7f7ed..bd8cf45a8 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -58,14 +58,6 @@ enum lttng_domain_type { LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN, }; -struct lttng_domain { - enum lttng_domain_type type; - union { - pid_t pid; - char exec_name[NAME_MAX]; - } attr; -}; - /* * Instrumentation type of tracing event. */ @@ -98,6 +90,14 @@ enum lttng_event_context_type { LTTNG_EVENT_CONTEXT_VPPID = 9, }; +struct lttng_domain { + enum lttng_domain_type type; + union { + pid_t pid; + char exec_name[NAME_MAX]; + } attr; +}; + /* Perf counter attributes */ struct lttng_event_perf_counter_ctx { uint32_t type; @@ -138,6 +138,7 @@ struct lttng_event_function_attr { struct lttng_event { char name[LTTNG_SYMBOL_NAME_LEN]; enum lttng_event_type type; + uint32_t enabled; /* Per event type configuration */ union { struct lttng_event_probe_attr probe; @@ -162,6 +163,7 @@ struct lttng_channel_attr { */ struct lttng_channel { char name[NAME_MAX]; + uint32_t enabled; struct lttng_channel_attr attr; }; @@ -209,13 +211,44 @@ extern int lttng_create_session(const char *name, const char *path); extern int lttng_destroy_session(const char *name); /* - * List tracing sessions. + * List all tracing sessions. * - * Return the size of the "lttng_session" array. Caller must free(3) the - * returned data. + * Return the size of the "lttng_session" array. Caller must free(3). */ extern int lttng_list_sessions(struct lttng_session **sessions); +/* + * List registered domain(s) of the session. + * + * Return the size of the "lttng_domain" array. Caller must free(3). + */ +extern int lttng_list_domains(const char *session_name, + struct lttng_domain **domains); + +/* + * List channel(s) of a session. + * + * Return the size of the "lttng_channel" array. Caller must free(3). + */ +extern int lttng_list_channels(struct lttng_domain *domain, + const char *session_name, struct lttng_channel **channels); + +/* + * List event(s) of a session channel. + * + * Return the size of the "lttng_event" array. Caller must free(3). + */ +extern int lttng_list_events(struct lttng_domain *domain, + const char *session_name, const char *channel_name, + struct lttng_event **events); + +/* + * List available kernel tracing events + * + * Return the size of the "lttng_event" array. Caller must free(3). + */ +extern int lttng_list_kernel_events(struct lttng_event **events); + /* * Check if a session daemon is alive. */ @@ -304,6 +337,6 @@ extern int lttng_disable_channel(struct lttng_domain *domain, * * Return the size of the allocated event list. Caller must free(3) the data. */ -extern int lttng_list_events(struct lttng_domain *domain, char **event_list); +//extern int lttng_list_events(struct lttng_domain *domain, char **event_list); #endif /* _LTTNG_H */ diff --git a/liblttngctl/liblttngctl.c b/liblttngctl/liblttngctl.c index e0a815882..0cc3268f7 100644 --- a/liblttngctl/liblttngctl.c +++ b/liblttngctl/liblttngctl.c @@ -278,6 +278,26 @@ end: return ret; } +/* + * Copy domain to lttcomm_session_msg domain. + * + * Return -1 if the domain is unkown. + */ +static int copy_lttng_domain(struct lttng_domain *dom) +{ + switch (dom->type) { + case LTTNG_DOMAIN_KERNEL: + case LTTNG_DOMAIN_UST: + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: + memcpy(&lsm.domain, dom, sizeof(struct lttng_domain)); + return 0; + default: + return -1; + } +} + /* * Start tracing for all trace of the session. */ @@ -448,28 +468,18 @@ int lttng_disable_channel(struct lttng_domain *domain, const char *name) } /* - * List all available events in the kernel. + * List all available kernel events. * * Return the size (bytes) of the list and set the event_list array. * On error, return negative value. */ -int lttng_list_events(struct lttng_domain *domain, char **event_list) +int lttng_list_kernel_events(struct lttng_event **events) { int ret; - switch (domain->type) { - case LTTNG_DOMAIN_KERNEL: - ret = ask_sessiond(LTTNG_KERNEL_LIST_EVENTS, (void **) event_list); - break; - case LTTNG_DOMAIN_UST: - ret = LTTCOMM_NOT_IMPLEMENTED; - break; - default: - ret = LTTCOMM_UNKNOWN_DOMAIN; - break; - }; + ret = ask_sessiond(LTTNG_KERNEL_LIST_EVENTS, (void **) events); - return ret; + return ret / sizeof(struct lttng_event); } /* @@ -521,6 +531,68 @@ int lttng_list_sessions(struct lttng_session **sessions) return ret / sizeof(struct lttng_session); } +/* + * List domain of a session. + */ +int lttng_list_domains(const char *session_name, struct lttng_domain **domains) +{ + int ret; + + strncpy(lsm.session_name, session_name, NAME_MAX); + ret = ask_sessiond(LTTNG_LIST_DOMAINS, (void**) domains); + if (ret < 0) { + return ret; + } + + return ret / sizeof(struct lttng_domain); +} + +/* + * List channels of a session + */ +int lttng_list_channels(struct lttng_domain *domain, + const char *session_name, struct lttng_channel **channels) +{ + int ret; + + strncpy(lsm.session_name, session_name, NAME_MAX); + ret = copy_lttng_domain(domain); + if (ret < 0) { + return -LTTCOMM_UNKNOWN_DOMAIN; + } + + ret = ask_sessiond(LTTNG_LIST_CHANNELS, (void**) channels); + if (ret < 0) { + return ret; + } + + return ret / sizeof(struct lttng_channel); +} + +/* + * List events of a session channel. + */ +int lttng_list_events(struct lttng_domain *domain, + const char *session_name, const char *channel_name, + struct lttng_event **events) +{ + int ret; + + strncpy(lsm.session_name, session_name, NAME_MAX); + strncpy(lsm.u.list.channel_name, channel_name, NAME_MAX); + ret = copy_lttng_domain(domain); + if (ret < 0) { + return -LTTCOMM_UNKNOWN_DOMAIN; + } + + ret = ask_sessiond(LTTNG_LIST_EVENTS, (void**) events); + if (ret < 0) { + return ret; + } + + return ret / sizeof(struct lttng_event); +} + /* * Set session name for the current lsm. */ diff --git a/liblttsessiondcomm/liblttsessiondcomm.h b/liblttsessiondcomm/liblttsessiondcomm.h index ab9fd7b5a..b1e006a02 100644 --- a/liblttsessiondcomm/liblttsessiondcomm.h +++ b/liblttsessiondcomm/liblttsessiondcomm.h @@ -53,10 +53,10 @@ enum lttcomm_sessiond_command { /* Session daemon context command */ LTTNG_CREATE_SESSION, LTTNG_DESTROY_SESSION, - LTTNG_LIST_SESSIONS, - LTTNG_LIST_TRACES, + LTTNG_LIST_CHANNELS, + LTTNG_LIST_DOMAINS, LTTNG_LIST_EVENTS, - LTTNG_LIST_TRACEABLE_APPS, + LTTNG_LIST_SESSIONS, LTTNG_START_TRACE, LTTNG_STOP_TRACE, }; @@ -128,7 +128,7 @@ struct lttcomm_session_msg { u32 cmd_type; /* enum lttcomm_sessiond_command */ char session_name[NAME_MAX]; char path[PATH_MAX]; - pid_t pid; + struct lttng_domain domain; union { struct { char channel_name[NAME_MAX]; @@ -149,6 +149,10 @@ struct lttcomm_session_msg { char event_name[NAME_MAX]; struct lttng_event_context ctx; } context; + /* List */ + struct { + char channel_name[NAME_MAX]; + } list; } u; }; diff --git a/ltt-sessiond/kernel-ctl.c b/ltt-sessiond/kernel-ctl.c index ef3afb714..09a3763eb 100644 --- a/ltt-sessiond/kernel-ctl.c +++ b/ltt-sessiond/kernel-ctl.c @@ -545,18 +545,16 @@ error: } /* - * kernel_list_events - * - * Get the event list from the kernel tracer and return that list in the CTF - * format. + * Get the event list from the kernel tracer and return the number of elements. */ -ssize_t kernel_list_events(int tracer_fd, char **list) +ssize_t kernel_list_events(int tracer_fd, struct lttng_event **events) { - int fd; - char *buf, *line = NULL; - size_t nb, nbmem, total = 0; + int fd, pos; + char *event; + size_t nbmem, count = 0; ssize_t size; FILE *fp; + struct lttng_event *elist; fd = kernctl_tracepoint_list(tracer_fd); if (fd < 0) { @@ -575,29 +573,29 @@ ssize_t kernel_list_events(int tracer_fd, char **list) * See kernel-ctl.h for explanation of this value */ nbmem = KERNEL_EVENT_LIST_SIZE; - buf = malloc(nbmem); + elist = malloc(sizeof(struct lttng_event) * nbmem); - while ((size = getline(&line, &nb, fp)) != -1) { - if (total + size > nbmem) { + while ((size = fscanf(fp, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { + if (count > nbmem) { DBG("Reallocating event list from %zd to %zd bytes", nbmem, - total + size + KERNEL_EVENT_LIST_SIZE); + nbmem + KERNEL_EVENT_LIST_SIZE); /* Adding the default size again */ - nbmem = total + size + KERNEL_EVENT_LIST_SIZE; - buf = realloc(buf, nbmem); - if (buf == NULL) { + nbmem += KERNEL_EVENT_LIST_SIZE; + elist = realloc(elist, nbmem); + if (elist == NULL) { perror("realloc list events"); goto error; } } - memcpy(buf + total, line, size); - total += size; + strncpy(elist[count].name, event, strlen(event)); + count++; } - *list = buf; + *events = elist; - DBG("Kernel list events done"); + DBG("Kernel list events done (%ld events)", count); - return total; + return count; error: return -1; diff --git a/ltt-sessiond/kernel-ctl.h b/ltt-sessiond/kernel-ctl.h index 5f3306bc1..22250417d 100644 --- a/ltt-sessiond/kernel-ctl.h +++ b/ltt-sessiond/kernel-ctl.h @@ -49,7 +49,7 @@ int kernel_flush_buffer(struct ltt_kernel_channel *channel); int kernel_metadata_flush_buffer(int fd); int kernel_start_session(struct ltt_kernel_session *session); int kernel_stop_session(struct ltt_kernel_session *session); -ssize_t kernel_list_events(int tracer_fd, char **event_list); +ssize_t kernel_list_events(int tracer_fd, struct lttng_event **event_list); void kernel_wait_quiescent(int fd); #endif /* _LTT_KERNEL_CTL_H */ diff --git a/ltt-sessiond/main.c b/ltt-sessiond/main.c index e069c1316..fc1ef9224 100644 --- a/ltt-sessiond/main.c +++ b/ltt-sessiond/main.c @@ -416,7 +416,7 @@ static int setup_lttng_msg(struct command_ctx *cmd_ctx, size_t size) /* Copy common data */ cmd_ctx->llm->cmd_type = cmd_ctx->lsm->cmd_type; - cmd_ctx->llm->pid = cmd_ctx->lsm->pid; + cmd_ctx->llm->pid = cmd_ctx->lsm->domain.attr.pid; cmd_ctx->llm->data_size = size; cmd_ctx->lttng_msg_size = sizeof(struct lttcomm_lttng_msg) + buf_size; @@ -1124,7 +1124,7 @@ static struct lttng_channel *init_default_channel(char *name) } if (snprintf(chan->name, NAME_MAX, "%s", name) < 0) { - perror("snprintf defautl channel name"); + perror("snprintf channel name"); return NULL; } @@ -1190,6 +1190,68 @@ static void list_lttng_sessions(struct lttng_session *sessions) } } +/* + * Fill lttng_channel array of all channels. + */ +static void list_lttng_channels(struct ltt_session *session, + struct lttng_channel *channels) +{ + int i = 0; + struct ltt_kernel_channel *kchan; + + DBG("Listing channels for session %s", session->name); + + /* Kernel channels */ + if (session->kernel_session != NULL) { + cds_list_for_each_entry(kchan, &session->kernel_session->channel_list.head, list) { + /* Copy lttng_channel struct to array */ + memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel)); + channels[i].enabled = kchan->enabled; + i++; + } + } + + /* TODO: Missing UST listing */ +} + +/* + * Fill lttng_event array of all events in the channel. + */ +static void list_lttng_events(struct ltt_kernel_channel *kchan, + struct lttng_event *events) +{ + /* + * TODO: This is ONLY kernel. Need UST support. + */ + int i = 0; + struct ltt_kernel_event *event; + + DBG("Listing events for channel %s", kchan->channel->name); + + /* Kernel channels */ + cds_list_for_each_entry(event, &kchan->events_list.head , list) { + strncpy(events[i].name, event->event->name, LTTNG_SYMBOL_NAME_LEN); + events[i].enabled = event->enabled; + switch (event->event->instrumentation) { + case LTTNG_KERNEL_TRACEPOINT: + events[i].type = LTTNG_EVENT_TRACEPOINT; + break; + case LTTNG_KERNEL_KPROBE: + case LTTNG_KERNEL_KRETPROBE: + events[i].type = LTTNG_EVENT_PROBE; + memcpy(&events[i].attr.probe, &event->event->u.kprobe, + sizeof(struct lttng_kernel_kprobe)); + break; + case LTTNG_KERNEL_FUNCTION: + events[i].type = LTTNG_EVENT_FUNCTION; + memcpy(&events[i].attr.ftrace, &event->event->u.ftrace, + sizeof(struct lttng_kernel_function)); + break; + } + i++; + } +} + /* * Process the command requested by the lttng client within the command * context structure. This function make sure that the return structure (llm) @@ -1207,9 +1269,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) switch (cmd_ctx->lsm->cmd_type) { case LTTNG_CREATE_SESSION: case LTTNG_LIST_SESSIONS: - case LTTNG_LIST_EVENTS: case LTTNG_KERNEL_LIST_EVENTS: - case LTTNG_LIST_TRACEABLE_APPS: break; default: DBG("Getting session %s by name", cmd_ctx->lsm->session_name); @@ -1570,11 +1630,11 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case LTTNG_KERNEL_ENABLE_ALL_EVENT: { - int pos, size; - char *event_list, *event, *ptr, *channel_name; + int size, i; + char *channel_name; struct ltt_kernel_channel *kchan; struct ltt_kernel_event *ev; - struct lttng_event ev_attr; + struct lttng_event *event_list; struct lttng_channel *chan; /* Setup lttng message with no payload */ @@ -1624,23 +1684,17 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto error; } - ptr = event_list; - while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { - ev = get_kernel_event_by_name(event, kchan); + for (i = 0; i < size; i++) { + ev = get_kernel_event_by_name(event_list[i].name, kchan); if (ev == NULL) { - strncpy(ev_attr.name, event, LTTNG_SYM_NAME_LEN); /* Default event type for enable all */ - ev_attr.type = LTTNG_EVENT_TRACEPOINT; + event_list[i].type = LTTNG_EVENT_TRACEPOINT; /* Enable each single tracepoint event */ - ret = kernel_create_event(&ev_attr, kchan); + ret = kernel_create_event(&event_list[i], kchan); if (ret < 0) { /* Ignore error here and continue */ } } - - /* Move pointer to the next line */ - ptr += pos + 1; - free(event); } free(event_list); @@ -1652,12 +1706,12 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case LTTNG_KERNEL_LIST_EVENTS: { - char *event_list; + struct lttng_event *events; ssize_t size = 0; DBG("Listing kernel events"); - size = kernel_list_events(kernel_tracer_fd, &event_list); + size = kernel_list_events(kernel_tracer_fd, &events); if (size < 0) { ret = LTTCOMM_KERN_LIST_FAIL; goto error; @@ -1667,15 +1721,16 @@ static int process_client_msg(struct command_ctx *cmd_ctx) * 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, size); + ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event) * size); if (ret < 0) { goto setup_error; } /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, event_list, size); + memcpy(cmd_ctx->llm->payload, events, + sizeof(struct lttng_event) * size); - free(event_list); + free(events); ret = LTTCOMM_OK; break; @@ -1844,92 +1899,124 @@ static int process_client_msg(struct command_ctx *cmd_ctx) break; } /* - case LTTNG_LIST_TRACES: + case UST_CREATE_TRACE: { - unsigned int trace_count; + ret = setup_lttng_msg(cmd_ctx, 0); + if (ret < 0) { + goto setup_error; + } - trace_count = get_trace_count_per_session(cmd_ctx->session); - if (trace_count == 0) { - ret = LTTCOMM_NO_TRACE; + ret = ust_create_trace(cmd_ctx); + if (ret < 0) { goto error; } - - ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_trace) * trace_count); + break; + } + case UST_START_TRACE: + { + ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } - get_traces_per_session(cmd_ctx->session, - (struct lttng_trace *)(cmd_ctx->llm->payload)); - - ret = LTTCOMM_OK; + ret = ust_start_trace(cmd_ctx); + if (ret < 0) { + goto setup_error; + } break; } - */ - /* - case UST_CREATE_TRACE: + case UST_STOP_TRACE: { ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } - ret = ust_create_trace(cmd_ctx); + ret = ust_stop_trace(cmd_ctx); if (ret < 0) { - goto error; + goto setup_error; } break; } */ - case LTTNG_LIST_TRACEABLE_APPS: + case LTTNG_LIST_DOMAINS: { - unsigned int app_count; + size_t nb_dom; - app_count = get_app_count(); - DBG("Traceable application count : %d", app_count); - if (app_count == 0) { - ret = LTTCOMM_NO_APPS; - goto error; + if (cmd_ctx->session->kernel_session != NULL) { + nb_dom++; } - ret = setup_lttng_msg(cmd_ctx, sizeof(pid_t) * app_count); + nb_dom += cmd_ctx->session->ust_trace_count; + + ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_domain) * nb_dom); if (ret < 0) { goto setup_error; } - get_app_list_pids((pid_t *)(cmd_ctx->llm->payload)); + ((struct lttng_domain *)(cmd_ctx->llm->payload))[0].type = + LTTNG_DOMAIN_KERNEL; + /* TODO: User-space tracer domain support */ ret = LTTCOMM_OK; break; } - /* - case UST_START_TRACE: + case LTTNG_LIST_CHANNELS: { - ret = setup_lttng_msg(cmd_ctx, 0); - if (ret < 0) { - goto setup_error; + /* + * TODO: Only kernel channels are listed here. UST listing + * is needed on lttng-ust 2.0 release. + */ + size_t nb_chan = 0; + if (cmd_ctx->session->kernel_session != NULL) { + nb_chan += cmd_ctx->session->kernel_session->channel_count; } - ret = ust_start_trace(cmd_ctx); + ret = setup_lttng_msg(cmd_ctx, + sizeof(struct lttng_channel) * nb_chan); if (ret < 0) { goto setup_error; } + + list_lttng_channels(cmd_ctx->session, + (struct lttng_channel *)(cmd_ctx->llm->payload)); + + ret = LTTCOMM_OK; break; } - case UST_STOP_TRACE: + case LTTNG_LIST_EVENTS: { - ret = setup_lttng_msg(cmd_ctx, 0); - if (ret < 0) { - goto setup_error; + /* + * TODO: Only kernel events are listed here. UST listing + * is needed on lttng-ust 2.0 release. + */ + size_t nb_event = 0; + struct ltt_kernel_channel *kchan = NULL; + + if (cmd_ctx->session->kernel_session != NULL) { + kchan = get_kernel_channel_by_name(cmd_ctx->lsm->u.list.channel_name, + cmd_ctx->session->kernel_session); + if (kchan == NULL) { + ret = LTTCOMM_KERN_CHAN_NOT_FOUND; + goto error; + } + nb_event += kchan->event_count; } - ret = ust_stop_trace(cmd_ctx); + ret = setup_lttng_msg(cmd_ctx, + sizeof(struct lttng_event) * nb_event); if (ret < 0) { goto setup_error; } + + DBG("Listing events (%ld events)", nb_event); + + list_lttng_events(kchan, + (struct lttng_event *)(cmd_ctx->llm->payload)); + + ret = LTTCOMM_OK; break; } - */ case LTTNG_LIST_SESSIONS: { lock_session_list(); diff --git a/lttng/commands/list.c b/lttng/commands/list.c index 0b4afa308..bce40ff6c 100644 --- a/lttng/commands/list.c +++ b/lttng/commands/list.c @@ -17,6 +17,7 @@ */ #define _GNU_SOURCE +#include #include #include #include @@ -25,26 +26,27 @@ #include "../cmd.h" static int opt_pid; -static int opt_channels; +static int opt_userspace; +static int opt_kernel; +static char *opt_channel; +static int opt_domain; + +const char *indent4 = " "; +const char *indent6 = " "; +const char *indent8 = " "; enum { OPT_HELP = 1, - OPT_EVENTS, - OPT_KERNEL, - OPT_APPS, - OPT_SESSIONS, - OPT_CHANNEL, }; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, - {"events", 'e', POPT_ARG_NONE, 0, OPT_EVENTS, 0, 0}, - {"kernel", 'k', POPT_ARG_NONE, 0, OPT_KERNEL, 0, 0}, - {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0}, - {"apps", 'a', POPT_ARG_NONE, 0, OPT_APPS, 0, 0}, - {"session", 's', POPT_ARG_NONE, 0, OPT_SESSIONS, 0, 0}, - {"channel", 'c', POPT_ARG_VAL, &opt_channels, 1, 0, 0}, + {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0}, + {"userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0}, + {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0}, + {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0}, + {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; @@ -53,26 +55,31 @@ static struct poptOption long_options[] = { */ static void usage(FILE *ofp) { - fprintf(ofp, "usage: lttng list [options] []\n"); + fprintf(ofp, "usage: lttng list [[-k] [-u] [-p PID] [SESSION []]]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "With no arguments, list available tracing session(s)\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "With -k alone, list available kernel events\n"); + fprintf(ofp, "With -u alone, list available userspace events\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -k, --kernel Select kernel domain\n"); + fprintf(ofp, " -u, --userspace Select user-space domain.\n"); + fprintf(ofp, " -p, --pid PID List user-space events by PID\n"); fprintf(ofp, "\n"); - fprintf(ofp, " -h, --help Show this help\n"); - fprintf(ofp, " -e, --events List all available instrumentation\n"); - fprintf(ofp, " -k, --kernel List kernel instrumentation\n"); - fprintf(ofp, " -p, --pid PID List user-space instrumentation by PID\n"); - fprintf(ofp, " -a, --apps List traceable user-space applications/pids\n"); - fprintf(ofp, " -s, --sessions List tracing session\n"); + fprintf(ofp, "Options:\n"); + fprintf(ofp, " -c, --channel NAME List details of a channel\n"); + fprintf(ofp, " -d, --domain List available domain(s)\n"); fprintf(ofp, "\n"); } /* - * get_cmdline_by_pid + * Get command line from /proc for a specific pid. * - * Get command line from /proc for a specific pid. - * - * On success, return an allocated string pointer pointing to the proc - * cmdline. - * On error, return NULL. + * On success, return an allocated string pointer to the proc cmdline. + * On error, return NULL. */ +#ifdef DISABLE static char *get_cmdline_by_pid(pid_t pid) { int ret; @@ -97,36 +104,28 @@ static char *get_cmdline_by_pid(pid_t pid) end: return cmdline; } +#endif /* DISABLE */ /* - * list_kernel - * - * Ask for all trace events in the kernel and pretty print them. + * Ask for all trace events in the kernel and pretty print them. */ -static int list_kernel(void) +static int list_kernel_events(void) { - int ret, pos, size; - char *event_list, *event, *ptr; - struct lttng_domain dom; + int i, size; + struct lttng_event *event_list; DBG("Getting all tracing events"); - dom.type = LTTNG_DOMAIN_KERNEL; - - ret = lttng_list_events(&dom, &event_list); - if (ret < 0) { - ERR("Unable to list kernel instrumentation"); - return ret; + size = lttng_list_kernel_events(&event_list); + if (size < 0) { + ERR("Unable to list kernel events"); + return size; } - MSG("Kernel tracepoints:\n-------------"); + MSG("Kernel events:\n-------------"); - ptr = event_list; - while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { - MSG(" - %s", event); - /* Move pointer to the next line */ - ptr += pos + 1; - free(event); + for (i = 0; i < size; i++) { + MSG(" %s", event_list[i].name); } free(event_list); @@ -135,114 +134,248 @@ static int list_kernel(void) } /* - * list_sessions - * - * Get the list of available sessions from the session daemon and print it to - * user. + * List events of channel of session and domain. */ -static int list_sessions(void) +static int list_events(struct lttng_domain *dom, + const char *session_name, const char *channel_name) { int ret, count, i; - struct lttng_session *sessions; + struct lttng_event *events = NULL; - count = lttng_list_sessions(&sessions); - DBG("Session count %d", count); + count = lttng_list_events(dom, session_name, channel_name, &events); if (count < 0) { ret = count; goto error; } - MSG("Available sessions:"); + MSG("\n%sEvents:", indent4); + if (count == 0) { + MSG("%sNone", indent6); + goto end; + } + for (i = 0; i < count; i++) { - MSG(" %d) %s (%s)", i+1, sessions[i].name, sessions[i].path); + switch (events[i].type) { + case LTTNG_EVENT_TRACEPOINT: + MSG("%s%s (type: tracepoint) [enabled: %d]", indent6, + events[i].name, events[i].enabled); + break; + case LTTNG_EVENT_PROBE: + MSG("%s%s (type: probe) [enabled: %d]", indent6, + events[i].name, events[i].enabled); + if (events[i].attr.probe.addr != 0) { + MSG("%saddr: 0x%" PRIx64, indent8, events[i].attr.probe.addr); + } else { + MSG("%soffset: 0x%" PRIx64, indent8, events[i].attr.probe.offset); + MSG("%ssymbol: %s", indent8, events[i].attr.probe.symbol_name); + } + break; + case LTTNG_EVENT_FUNCTION: + case LTTNG_EVENT_FUNCTION_ENTRY: + MSG("%s%s (type: function) [enabled: %d]", indent6, + events[i].name, events[i].enabled); + MSG("%ssymbol: \"%s\"", indent8, events[i].attr.ftrace.symbol_name); + break; + } } - free(sessions); + MSG(""); - return CMD_SUCCESS; +end: + if (events) { + free(events); + } + ret = CMD_SUCCESS; error: return ret; } /* - * list_apps + * Pretty print channel + */ +static void print_channel(struct lttng_channel *channel) +{ + MSG("- %s (enabled: %d):\n", channel->name, channel->enabled); + + MSG("%sAttributes:", indent4); + MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite); + MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size); + MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf); + MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval); + MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval); + switch (channel->attr.output) { + case LTTNG_EVENT_SPLICE: + MSG("%soutput: splice()", indent6); + break; + case LTTNG_EVENT_MMAP: + MSG("%soutput: mmap()", indent6); + break; + } +} + +/* + * List channel(s) of session and domain. * - * Get the UST traceable pid list and print them to the user. + * If channel_name is NULL, all channels are listed. */ -static int list_apps(void) +static int list_channels(struct lttng_domain *dom, + const char *session_name, const char *channel_name) { - int i, ret, count; - pid_t *pids; - char *cmdline; + int count, i, ret = CMD_SUCCESS; + unsigned int chan_found = 0; + struct lttng_channel *channels = NULL; - count = -1; - //count = lttng_ust_list_traceable_apps(&pids); + DBG("Listing channel(s) (%s)", channel_name); + + count = lttng_list_channels(dom, session_name, &channels); if (count < 0) { ret = count; goto error; + } else if (count == 0) { + MSG("No channel found"); + goto end; } - MSG("LTTng UST traceable application [name (pid)]:"); - for (i=0; i < count; i++) { - cmdline = get_cmdline_by_pid(pids[i]); - if (cmdline == NULL) { - MSG("\t(not running) (%d)", pids[i]); - continue; + if (channel_name == NULL) { + MSG("Channels:\n-------------"); + } + + for (i = 0; i < count; i++) { + if (channel_name != NULL) { + if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) { + chan_found = 1; + } else { + continue; + } + } + print_channel(&channels[i]); + + /* Listing events per channel */ + ret = list_events(dom, session_name, channels[i].name); + if (ret < 0) { + MSG("%s", lttng_get_readable_code(ret)); + } + + if (chan_found) { + break; } - MSG("\t%s (%d)", cmdline, pids[i]); - free(cmdline); } - /* Allocated by lttng_ust_list_apps() */ - free(pids); + if (!chan_found && channel_name != NULL) { + MSG("Channel %s not found", channel_name); + } - return CMD_SUCCESS; +end: + free(channels); + ret = CMD_SUCCESS; error: return ret; } /* - * list_pid + * List available tracing session. List only basic information. * - * List all instrumentation for a specific pid + * If session_name is NULL, all sessions are listed. */ -/* -static int list_pid(int pid) +static int list_sessions(const char *session_name) { - int ret; + int ret, count, i; + unsigned int session_found = 0; + struct lttng_session *sessions; + + count = lttng_list_sessions(&sessions); + DBG("Session count %d", count); + if (count < 0) { + ret = count; + goto error; + } + + if (session_name == NULL) { + MSG("Available tracing sessions:"); + } + + for (i = 0; i < count; i++) { + if (session_name != NULL) { + if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { + session_found = 1; + MSG("Tracing session %s:", session_name); + MSG("%sTrace path: %s\n", indent4, sessions[i].path); + break; + } + } + + MSG(" %d) %s (%s)", i + 1, sessions[i].name, sessions[i].path); + + if (session_found) { + break; + } + } + + free(sessions); + + if (!session_found && session_name != NULL) { + MSG("Session %s not found", session_name); + } + + if (session_name == NULL) { + MSG("\nUse lttng list -s for a detail listing"); + } return CMD_SUCCESS; error: return ret; } -*/ /* - * list_executable - * - * List all instrumentation for an executable on the system + * List available domain(s) for a session. */ -/* -static int list_executable(char *name) +static int list_domains(const char *session_name) { + int i, count, ret = CMD_SUCCESS; + struct lttng_domain *domains = NULL; + + MSG("Domains:\n-------------"); + + count = lttng_list_domains(session_name, &domains); + if (count < 0) { + ret = count; + goto error; + } else if (count == 0) { + MSG(" None"); + goto end; + } + + for (i = 0; i < count; i++) { + switch (domains[i].type) { + case LTTNG_DOMAIN_KERNEL: + MSG(" - Kernel"); + default: + break; + } + } + +end: + free(domains); + +error: + return ret; } -*/ /* - * cmd_list - * - * The 'list ' first level command + * The 'list ' first level command */ int cmd_list(int argc, const char **argv) { - int opt, ret = CMD_SUCCESS; - const char *command_name; + int opt, i, ret = CMD_SUCCESS; + const char *session_name; static poptContext pc; + struct lttng_domain domain; + struct lttng_domain *domains = NULL; - if (argc < 2) { + if (argc < 1) { usage(stderr); goto end; } @@ -255,18 +388,6 @@ int cmd_list(int argc, const char **argv) case OPT_HELP: usage(stderr); goto end; - case OPT_EVENTS: - ret = CMD_NOT_IMPLEMENTED; - goto end; - case OPT_APPS: - ret = list_apps(); - break; - case OPT_KERNEL: - ret = list_kernel(); - break; - case OPT_SESSIONS: - ret = list_sessions(); - break; default: usage(stderr); ret = CMD_UNDEFINED; @@ -274,17 +395,76 @@ int cmd_list(int argc, const char **argv) } } - if (opt_pid != 0) { - //ret = list_pid(pid); - ret = CMD_NOT_IMPLEMENTED; + if (opt_userspace || opt_pid != 0) { + MSG("*** Userspace tracing not implemented ***\n"); } - command_name = poptGetArg(pc); - if (command_name != NULL) { - // ret = list_executable(command_name); - ret = CMD_NOT_IMPLEMENTED; + /* Get session name (trailing argument) */ + session_name = poptGetArg(pc); + DBG("Session name: %s", session_name); + + if (session_name == NULL) { + if (opt_kernel) { + ret = list_kernel_events(); + if (ret < 0) { + goto end; + } + } else { + ret = list_sessions(NULL); + if (ret < 0) { + goto end; + } + } + } else { + /* List session attributes */ + ret = list_sessions(session_name); + if (ret < 0) { + goto end; + } + + /* Domain listing */ + if (opt_domain) { + ret = list_domains(session_name); + goto end; + } + + if (opt_kernel) { + domain.type = LTTNG_DOMAIN_KERNEL; + /* Channel listing */ + ret = list_channels(&domain, session_name, opt_channel); + if (ret < 0) { + goto end; + } + } else if (opt_userspace) { + /* TODO: Userspace domain */ + } else { + /* We want all domain(s) */ + ret = lttng_list_domains(session_name, &domains); + if (ret < 0) { + goto end; + } + + for (i = 0; i < ret; i++) { + switch (domains[i].type) { + case LTTNG_DOMAIN_KERNEL: + MSG("=== Domain: Kernel ===\n"); + break; + default: + MSG("=== Domain: Unimplemented ===\n"); + break; + } + + ret = list_channels(&domains[i], session_name, opt_channel); + if (ret < 0) { + goto end; + } + } + } } end: + if (domains) { + free(domains); + } return ret; } -- 2.34.1