Add support for --syscalls
[lttng-tools.git] / lttng / commands / list.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; only version 2
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <inttypes.h>
21 #include <popt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "../cmd.h"
27
28 static int opt_pid;
29 static int opt_userspace;
30 static int opt_kernel;
31 static char *opt_channel;
32 static int opt_domain;
33
34 const char *indent4 = " ";
35 const char *indent6 = " ";
36 const char *indent8 = " ";
37
38 enum {
39 OPT_HELP = 1,
40 };
41
42 static struct lttng_handle *handle;
43
44 static struct poptOption long_options[] = {
45 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
46 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
47 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
48 {"userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0},
49 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
50 {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
51 {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
52 {0, 0, 0, 0, 0, 0, 0}
53 };
54
55 /*
56 * usage
57 */
58 static void usage(FILE *ofp)
59 {
60 fprintf(ofp, "usage: lttng list [[-k] [-u] [-p PID] [SESSION [<options>]]]\n");
61 fprintf(ofp, "\n");
62 fprintf(ofp, "With no arguments, list available tracing session(s)\n");
63 fprintf(ofp, "\n");
64 fprintf(ofp, "With -k alone, list available kernel events\n");
65 fprintf(ofp, "With -u alone, list available userspace events\n");
66 fprintf(ofp, "\n");
67 fprintf(ofp, " -h, --help Show this help\n");
68 fprintf(ofp, " -k, --kernel Select kernel domain\n");
69 fprintf(ofp, " -u, --userspace Select user-space domain.\n");
70 fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
71 fprintf(ofp, "\n");
72 fprintf(ofp, "Options:\n");
73 fprintf(ofp, " -c, --channel NAME List details of a channel\n");
74 fprintf(ofp, " -d, --domain List available domain(s)\n");
75 fprintf(ofp, "\n");
76 }
77
78 /*
79 * Get command line from /proc for a specific pid.
80 *
81 * On success, return an allocated string pointer to the proc cmdline.
82 * On error, return NULL.
83 */
84 #ifdef DISABLE
85 static char *get_cmdline_by_pid(pid_t pid)
86 {
87 int ret;
88 FILE *fp;
89 char *cmdline = NULL;
90 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
91
92 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
93 fp = fopen(path, "r");
94 if (fp == NULL) {
95 goto end;
96 }
97
98 /* Caller must free() *cmdline */
99 cmdline = malloc(PATH_MAX);
100 ret = fread(cmdline, 1, PATH_MAX, fp);
101 if (ret < 0) {
102 perror("fread proc list");
103 }
104 fclose(fp);
105
106 end:
107 return cmdline;
108 }
109 #endif /* DISABLE */
110
111 /*
112 * Ask for all trace events in the kernel and pretty print them.
113 */
114 static int list_kernel_events(void)
115 {
116 int i, size;
117 struct lttng_event *event_list;
118
119 DBG("Getting all tracing events");
120
121 size = lttng_list_tracepoints(handle, &event_list);
122 if (size < 0) {
123 ERR("Unable to list kernel events");
124 return size;
125 }
126
127 MSG("Kernel events:\n-------------");
128
129 for (i = 0; i < size; i++) {
130 MSG(" %s", event_list[i].name);
131 }
132
133 free(event_list);
134
135 return CMD_SUCCESS;
136 }
137
138 /*
139 * List events of channel of session and domain.
140 */
141 static int list_events(const char *channel_name)
142 {
143 int ret, count, i;
144 struct lttng_event *events = NULL;
145
146 count = lttng_list_events(handle, channel_name, &events);
147 if (count < 0) {
148 ret = count;
149 goto error;
150 }
151
152 MSG("\n%sEvents:", indent4);
153 if (count == 0) {
154 MSG("%sNone", indent6);
155 goto end;
156 }
157
158 for (i = 0; i < count; i++) {
159 switch (events[i].type) {
160 case LTTNG_EVENT_TRACEPOINT:
161 MSG("%s%s (type: tracepoint) [enabled: %d]", indent6,
162 events[i].name, events[i].enabled);
163 break;
164 case LTTNG_EVENT_PROBE:
165 MSG("%s%s (type: probe) [enabled: %d]", indent6,
166 events[i].name, events[i].enabled);
167 if (events[i].attr.probe.addr != 0) {
168 MSG("%saddr: 0x%" PRIx64, indent8, events[i].attr.probe.addr);
169 } else {
170 MSG("%soffset: 0x%" PRIx64, indent8, events[i].attr.probe.offset);
171 MSG("%ssymbol: %s", indent8, events[i].attr.probe.symbol_name);
172 }
173 break;
174 case LTTNG_EVENT_FUNCTION:
175 case LTTNG_EVENT_FUNCTION_ENTRY:
176 MSG("%s%s (type: function) [enabled: %d]", indent6,
177 events[i].name, events[i].enabled);
178 MSG("%ssymbol: \"%s\"", indent8, events[i].attr.ftrace.symbol_name);
179 break;
180 case LTTNG_EVENT_SYSCALLS:
181 MSG("%s (type: syscalls) [enabled: %d]", indent6,
182 events[i].enabled);
183 break;
184 case LTTNG_EVENT_NOOP:
185 MSG("%s (type: noop) [enabled: %d]", indent6,
186 events[i].enabled);
187 break;
188 }
189 }
190
191 MSG("");
192
193 end:
194 if (events) {
195 free(events);
196 }
197 ret = CMD_SUCCESS;
198
199 error:
200 return ret;
201 }
202
203 /*
204 * Pretty print channel
205 */
206 static void print_channel(struct lttng_channel *channel)
207 {
208 MSG("- %s (enabled: %d):\n", channel->name, channel->enabled);
209
210 MSG("%sAttributes:", indent4);
211 MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite);
212 MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size);
213 MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf);
214 MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval);
215 MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval);
216 switch (channel->attr.output) {
217 case LTTNG_EVENT_SPLICE:
218 MSG("%soutput: splice()", indent6);
219 break;
220 case LTTNG_EVENT_MMAP:
221 MSG("%soutput: mmap()", indent6);
222 break;
223 }
224 }
225
226 /*
227 * List channel(s) of session and domain.
228 *
229 * If channel_name is NULL, all channels are listed.
230 */
231 static int list_channels(const char *channel_name)
232 {
233 int count, i, ret = CMD_SUCCESS;
234 unsigned int chan_found = 0;
235 struct lttng_channel *channels = NULL;
236
237 DBG("Listing channel(s) (%s)", channel_name);
238
239 count = lttng_list_channels(handle, &channels);
240 if (count < 0) {
241 ret = count;
242 goto error;
243 } else if (count == 0) {
244 MSG("No channel found");
245 goto end;
246 }
247
248 if (channel_name == NULL) {
249 MSG("Channels:\n-------------");
250 }
251
252 for (i = 0; i < count; i++) {
253 if (channel_name != NULL) {
254 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
255 chan_found = 1;
256 } else {
257 continue;
258 }
259 }
260 print_channel(&channels[i]);
261
262 /* Listing events per channel */
263 ret = list_events(channels[i].name);
264 if (ret < 0) {
265 MSG("%s", lttng_get_readable_code(ret));
266 }
267
268 if (chan_found) {
269 break;
270 }
271 }
272
273 if (!chan_found && channel_name != NULL) {
274 MSG("Channel %s not found", channel_name);
275 }
276
277 end:
278 free(channels);
279 ret = CMD_SUCCESS;
280
281 error:
282 return ret;
283 }
284
285 /*
286 * List available tracing session. List only basic information.
287 *
288 * If session_name is NULL, all sessions are listed.
289 */
290 static int list_sessions(const char *session_name)
291 {
292 int ret, count, i;
293 unsigned int session_found = 0;
294 struct lttng_session *sessions;
295
296 count = lttng_list_sessions(&sessions);
297 DBG("Session count %d", count);
298 if (count < 0) {
299 ret = count;
300 goto error;
301 }
302
303 if (session_name == NULL) {
304 MSG("Available tracing sessions:");
305 }
306
307 for (i = 0; i < count; i++) {
308 if (session_name != NULL) {
309 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
310 session_found = 1;
311 MSG("Tracing session %s:", session_name);
312 MSG("%sTrace path: %s\n", indent4, sessions[i].path);
313 break;
314 }
315 continue;
316 }
317
318 MSG(" %d) %s (%s)", i + 1, sessions[i].name, sessions[i].path);
319
320 if (session_found) {
321 break;
322 }
323 }
324
325 free(sessions);
326
327 if (!session_found && session_name != NULL) {
328 MSG("Session %s not found", session_name);
329 }
330
331 if (session_name == NULL) {
332 MSG("\nUse lttng list <session_name> for more details");
333 }
334
335 return CMD_SUCCESS;
336
337 error:
338 return ret;
339 }
340
341 /*
342 * List available domain(s) for a session.
343 */
344 static int list_domains(void)
345 {
346 int i, count, ret = CMD_SUCCESS;
347 struct lttng_domain *domains = NULL;
348
349 MSG("Domains:\n-------------");
350
351 count = lttng_list_domains(handle, &domains);
352 if (count < 0) {
353 ret = count;
354 goto error;
355 } else if (count == 0) {
356 MSG(" None");
357 goto end;
358 }
359
360 for (i = 0; i < count; i++) {
361 switch (domains[i].type) {
362 case LTTNG_DOMAIN_KERNEL:
363 MSG(" - Kernel");
364 default:
365 break;
366 }
367 }
368
369 end:
370 free(domains);
371
372 error:
373 return ret;
374 }
375
376 /*
377 * The 'list <options>' first level command
378 */
379 int cmd_list(int argc, const char **argv)
380 {
381 int opt, i, ret = CMD_SUCCESS;
382 const char *session_name;
383 static poptContext pc;
384 struct lttng_domain domain;
385 struct lttng_domain *domains = NULL;
386
387 if (argc < 1) {
388 usage(stderr);
389 goto end;
390 }
391
392 pc = poptGetContext(NULL, argc, argv, long_options, 0);
393 poptReadDefaultConfig(pc, 0);
394
395 while ((opt = poptGetNextOpt(pc)) != -1) {
396 switch (opt) {
397 case OPT_HELP:
398 usage(stderr);
399 goto end;
400 default:
401 usage(stderr);
402 ret = CMD_UNDEFINED;
403 goto end;
404 }
405 }
406
407 if (opt_userspace || opt_pid != 0) {
408 MSG("*** Userspace tracing not implemented ***\n");
409 }
410
411 /* Get session name (trailing argument) */
412 session_name = poptGetArg(pc);
413 DBG("Session name: %s", session_name);
414
415 if (opt_kernel) {
416 domain.type = LTTNG_DOMAIN_KERNEL;
417 }
418
419 handle = lttng_create_handle(session_name, &domain);
420 if (handle == NULL) {
421 goto end;
422 }
423
424 if (session_name == NULL) {
425 if (opt_kernel) {
426 ret = list_kernel_events();
427 if (ret < 0) {
428 goto end;
429 }
430 } else {
431 ret = list_sessions(NULL);
432 if (ret < 0) {
433 goto end;
434 }
435 }
436 } else {
437 /* List session attributes */
438 ret = list_sessions(session_name);
439 if (ret < 0) {
440 goto end;
441 }
442
443 /* Domain listing */
444 if (opt_domain) {
445 ret = list_domains();
446 goto end;
447 }
448
449 if (opt_kernel) {
450 /* Channel listing */
451 ret = list_channels(opt_channel);
452 if (ret < 0) {
453 goto end;
454 }
455 } else if (opt_userspace) {
456 /* TODO: Userspace domain */
457 } else {
458 /* We want all domain(s) */
459 ret = lttng_list_domains(handle, &domains);
460 if (ret < 0) {
461 goto end;
462 }
463
464 for (i = 0; i < ret; i++) {
465 switch (domains[i].type) {
466 case LTTNG_DOMAIN_KERNEL:
467 MSG("=== Domain: Kernel ===\n");
468 break;
469 default:
470 MSG("=== Domain: Unimplemented ===\n");
471 break;
472 }
473
474 /* Clean handle before creating a new one */
475 lttng_destroy_handle(handle);
476
477 handle = lttng_create_handle(session_name, &domains[i]);
478 if (handle == NULL) {
479 goto end;
480 }
481
482 ret = list_channels(opt_channel);
483 if (ret < 0) {
484 goto end;
485 }
486 }
487 }
488 }
489
490 end:
491 if (domains) {
492 free(domains);
493 }
494 lttng_destroy_handle(handle);
495
496 return ret;
497 }
This page took 0.039468 seconds and 4 git commands to generate.