X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=lttng%2Fcommands%2Flist.c;h=035269a5860ac8c43364ae2044f9f48be389c3fa;hp=52c44eeb652a73f638d0c8182426a62fdf84bbf6;hb=3e25cb206e0a0e8ae04f7eb1e310970baf01a323;hpb=6e2d116c6138874c0357b1afb1db5aa7cd80ceb6 diff --git a/lttng/commands/list.c b/lttng/commands/list.c index 52c44eeb6..035269a58 100644 --- a/lttng/commands/list.c +++ b/lttng/commands/list.c @@ -17,34 +17,41 @@ */ #define _GNU_SOURCE +#include #include #include #include #include +#include #include "../cmd.h" static int opt_pid; -static int opt_channels; +static int opt_userspace; +static char *opt_cmd_name; +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, + OPT_USERSPACE, }; +static struct lttng_handle *handle; + 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_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 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,25 +60,29 @@ 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, " -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, "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, "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. */ static char *get_cmdline_by_pid(pid_t pid) { @@ -89,157 +100,395 @@ static char *get_cmdline_by_pid(pid_t pid) /* Caller must free() *cmdline */ cmdline = malloc(PATH_MAX); ret = fread(cmdline, 1, PATH_MAX, fp); + if (ret < 0) { + perror("fread proc list"); + } fclose(fp); end: return cmdline; } +static +const char *active_string(int value) +{ + switch (value) { + case 0: return " [inactive]"; + case 1: return " [active]"; + case -1: return ""; + default: return NULL; + } +} + +static +const char *enabled_string(int value) +{ + switch (value) { + case 0: return " [disabled]"; + case 1: return " [enabled]"; + case -1: return ""; + default: return NULL; + } +} + /* - * list_kernel - * - * Ask for all trace events in the kernel and pretty print them. + * Pretty print single event. */ -static int list_kernel(void) +static void print_events(struct lttng_event *event) { - int ret, pos, size; - char *event_list, *event, *ptr; - struct lttng_domain dom; + switch (event->type) { + case LTTNG_EVENT_TRACEPOINT: + MSG("%s%s (type: tracepoint)%s", indent6, + event->name, enabled_string(event->enabled)); + break; + case LTTNG_EVENT_PROBE: + MSG("%s%s (type: probe)%s", indent6, + event->name, enabled_string(event->enabled)); + if (event->attr.probe.addr != 0) { + MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr); + } else { + MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset); + MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name); + } + break; + case LTTNG_EVENT_FUNCTION: + case LTTNG_EVENT_FUNCTION_ENTRY: + MSG("%s%s (type: function)%s", indent6, + event->name, enabled_string(event->enabled)); + MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name); + break; + case LTTNG_EVENT_SYSCALL: + MSG("%s (type: syscall)%s", indent6, + enabled_string(event->enabled)); + break; + case LTTNG_EVENT_NOOP: + MSG("%s (type: noop)%s", indent6, + enabled_string(event->enabled)); + break; + case LTTNG_EVENT_ALL: + /* We should never have "all" events in list. */ + assert(0); + break; + } +} - DBG("Getting all tracing events"); +/* + * Ask session daemon for all user space tracepoints available. + */ +static int list_ust_events(void) +{ + int i, size; + struct lttng_domain domain; + struct lttng_handle *handle; + struct lttng_event *event_list; + pid_t cur_pid = 0; - dom.type = LTTNG_DOMAIN_KERNEL; + DBG("Getting UST tracing events"); - ret = lttng_list_events(&dom, &event_list); - if (ret < 0) { - ERR("Unable to list kernel instrumentation"); - return ret; + domain.type = LTTNG_DOMAIN_UST; + + handle = lttng_create_handle(NULL, &domain); + if (handle == NULL) { + goto error; } - MSG("Kernel tracepoints:\n-------------"); + size = lttng_list_tracepoints(handle, &event_list); + if (size < 0) { + ERR("Unable to list UST events"); + return size; + } + + MSG("UST 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); + if (size == 0) { + MSG("None"); + } + + for (i = 0; i < size; i++) { + if (cur_pid != event_list[i].pid) { + cur_pid = event_list[i].pid; + MSG("\nPID: %d - Name: %s", cur_pid, get_cmdline_by_pid(cur_pid)); + } + print_events(&event_list[i]); } + MSG(""); + free(event_list); return CMD_SUCCESS; + +error: + return -1; } /* - * list_sessions - * - * Get the list of available sessions from the session daemon and print it to - * user. + * Ask for all trace events in the kernel and pretty print them. */ -static int list_sessions(void) +static int list_kernel_events(void) +{ + int i, size; + struct lttng_domain domain; + struct lttng_handle *handle; + struct lttng_event *event_list; + + DBG("Getting kernel tracing events"); + + domain.type = LTTNG_DOMAIN_KERNEL; + + handle = lttng_create_handle(NULL, &domain); + if (handle == NULL) { + goto error; + } + + size = lttng_list_tracepoints(handle, &event_list); + if (size < 0) { + ERR("Unable to list kernel events"); + return size; + } + + MSG("Kernel events:\n-------------"); + + for (i = 0; i < size; i++) { + print_events(&event_list[i]); + } + + MSG(""); + + free(event_list); + + return CMD_SUCCESS; + +error: + return -1; +} + +/* + * List events of channel of session and domain. + */ +static int list_events(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(handle, 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); + print_events(&events[i]); } - 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:%s\n", channel->name, enabled_string(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(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; + + DBG("Listing channel(s) (%s)", channel_name ? : ""); - count = -1; - //count = lttng_ust_list_traceable_apps(&pids); + count = lttng_list_channels(handle, &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(channels[i].name); + if (ret < 0) { + MSG("%s", lttng_strerror(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:%s", session_name, active_string(sessions[i].enabled)); + MSG("%sTrace path: %s\n", indent4, sessions[i].path); + break; + } + continue; + } + + MSG(" %d) %s (%s)%s", i + 1, sessions[i].name, sessions[i].path, active_string(sessions[i].enabled)); + + 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 for more details"); + } 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(void) { + int i, count, ret = CMD_SUCCESS; + struct lttng_domain *domains = NULL; + + MSG("Domains:\n-------------"); + + count = lttng_list_domains(handle, &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"); + break; + case LTTNG_DOMAIN_UST: + MSG(" - UST global"); + break; + 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; + unsigned int nb_domain; + 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; } @@ -252,17 +501,8 @@ 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(); + case OPT_USERSPACE: + opt_userspace = 1; break; default: usage(stderr); @@ -272,16 +512,105 @@ int cmd_list(int argc, const char **argv) } if (opt_pid != 0) { - //ret = list_pid(pid); - ret = CMD_NOT_IMPLEMENTED; + MSG("*** Userspace tracing not implemented for PID ***\n"); + } + + /* Get session name (trailing argument) */ + session_name = poptGetArg(pc); + DBG2("Session name: %s", session_name); + + if (opt_kernel) { + domain.type = LTTNG_DOMAIN_KERNEL; + } else if (opt_userspace) { + DBG2("Listing userspace global domain"); + domain.type = LTTNG_DOMAIN_UST; } - command_name = poptGetArg(pc); - if (command_name != NULL) { - // ret = list_executable(command_name); - ret = CMD_NOT_IMPLEMENTED; + handle = lttng_create_handle(session_name, &domain); + if (handle == NULL) { + goto end; + } + + if (session_name == NULL) { + if (!opt_kernel && !opt_userspace) { + ret = list_sessions(NULL); + if (ret < 0) { + goto end; + } + } + if (opt_kernel) { + ret = list_kernel_events(); + if (ret < 0) { + goto end; + } + } + if (opt_userspace) { + ret = list_ust_events(); + 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(); + goto end; + } + + if (opt_kernel) { + /* Channel listing */ + ret = list_channels(opt_channel); + if (ret < 0) { + goto end; + } + } else { + /* We want all domain(s) */ + nb_domain = lttng_list_domains(handle, &domains); + if (nb_domain < 0) { + ret = nb_domain; + goto end; + } + + for (i = 0; i < nb_domain; i++) { + switch (domains[i].type) { + case LTTNG_DOMAIN_KERNEL: + MSG("=== Domain: Kernel ===\n"); + break; + case LTTNG_DOMAIN_UST: + MSG("=== Domain: UST global ===\n"); + break; + default: + MSG("=== Domain: Unimplemented ===\n"); + break; + } + + /* Clean handle before creating a new one */ + lttng_destroy_handle(handle); + + handle = lttng_create_handle(session_name, &domains[i]); + if (handle == NULL) { + goto end; + } + + ret = list_channels(opt_channel); + if (ret < 0) { + goto end; + } + } + } } end: + if (domains) { + free(domains); + } + lttng_destroy_handle(handle); + return ret; }