Add support for --syscalls
[lttng-tools.git] / lttng / commands / list.c
CommitLineData
f3ed775e
DG
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
82a3637f
DG
6 * as published by the Free Software Foundation; only version 2
7 * of the License.
f3ed775e
DG
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
9f19cc17 20#include <inttypes.h>
f3ed775e
DG
21#include <popt.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
6e2d116c 26#include "../cmd.h"
f3ed775e
DG
27
28static int opt_pid;
9f19cc17
DG
29static int opt_userspace;
30static int opt_kernel;
31static char *opt_channel;
32static int opt_domain;
33
34const char *indent4 = " ";
35const char *indent6 = " ";
36const char *indent8 = " ";
f3ed775e
DG
37
38enum {
39 OPT_HELP = 1,
f3ed775e
DG
40};
41
cd80958d
DG
42static struct lttng_handle *handle;
43
f3ed775e
DG
44static struct poptOption long_options[] = {
45 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
46 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
9f19cc17
DG
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},
f3ed775e
DG
52 {0, 0, 0, 0, 0, 0, 0}
53};
54
55/*
56 * usage
57 */
58static void usage(FILE *ofp)
59{
9f19cc17
DG
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");
f3ed775e 71 fprintf(ofp, "\n");
9f19cc17
DG
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");
f3ed775e
DG
75 fprintf(ofp, "\n");
76}
77
78/*
9f19cc17 79 * Get command line from /proc for a specific pid.
f3ed775e 80 *
9f19cc17
DG
81 * On success, return an allocated string pointer to the proc cmdline.
82 * On error, return NULL.
f3ed775e 83 */
9f19cc17 84#ifdef DISABLE
f3ed775e
DG
85static 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);
f40799e8
DG
101 if (ret < 0) {
102 perror("fread proc list");
103 }
f3ed775e
DG
104 fclose(fp);
105
106end:
107 return cmdline;
108}
9f19cc17 109#endif /* DISABLE */
f3ed775e
DG
110
111/*
9f19cc17 112 * Ask for all trace events in the kernel and pretty print them.
f3ed775e 113 */
9f19cc17 114static int list_kernel_events(void)
f3ed775e 115{
9f19cc17
DG
116 int i, size;
117 struct lttng_event *event_list;
f3ed775e
DG
118
119 DBG("Getting all tracing events");
120
cd80958d 121 size = lttng_list_tracepoints(handle, &event_list);
9f19cc17
DG
122 if (size < 0) {
123 ERR("Unable to list kernel events");
124 return size;
f3ed775e
DG
125 }
126
9f19cc17 127 MSG("Kernel events:\n-------------");
f3ed775e 128
9f19cc17
DG
129 for (i = 0; i < size; i++) {
130 MSG(" %s", event_list[i].name);
f3ed775e
DG
131 }
132
133 free(event_list);
134
135 return CMD_SUCCESS;
136}
137
138/*
9f19cc17 139 * List events of channel of session and domain.
f3ed775e 140 */
cd80958d 141static int list_events(const char *channel_name)
f3ed775e
DG
142{
143 int ret, count, i;
9f19cc17 144 struct lttng_event *events = NULL;
f3ed775e 145
cd80958d 146 count = lttng_list_events(handle, channel_name, &events);
f3ed775e
DG
147 if (count < 0) {
148 ret = count;
149 goto error;
150 }
151
9f19cc17
DG
152 MSG("\n%sEvents:", indent4);
153 if (count == 0) {
154 MSG("%sNone", indent6);
155 goto end;
156 }
157
f3ed775e 158 for (i = 0; i < count; i++) {
9f19cc17
DG
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;
0133c199
MD
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;
9f19cc17 188 }
f3ed775e
DG
189 }
190
9f19cc17 191 MSG("");
f3ed775e 192
9f19cc17
DG
193end:
194 if (events) {
195 free(events);
196 }
197 ret = CMD_SUCCESS;
f3ed775e
DG
198
199error:
200 return ret;
201}
202
203/*
9f19cc17
DG
204 * Pretty print channel
205 */
206static 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.
f3ed775e 228 *
9f19cc17 229 * If channel_name is NULL, all channels are listed.
f3ed775e 230 */
cd80958d 231static int list_channels(const char *channel_name)
f3ed775e 232{
9f19cc17
DG
233 int count, i, ret = CMD_SUCCESS;
234 unsigned int chan_found = 0;
235 struct lttng_channel *channels = NULL;
f3ed775e 236
9f19cc17
DG
237 DBG("Listing channel(s) (%s)", channel_name);
238
cd80958d 239 count = lttng_list_channels(handle, &channels);
f3ed775e
DG
240 if (count < 0) {
241 ret = count;
242 goto error;
9f19cc17
DG
243 } else if (count == 0) {
244 MSG("No channel found");
245 goto end;
f3ed775e
DG
246 }
247
9f19cc17
DG
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 */
cd80958d 263 ret = list_events(channels[i].name);
9f19cc17
DG
264 if (ret < 0) {
265 MSG("%s", lttng_get_readable_code(ret));
266 }
267
268 if (chan_found) {
269 break;
f3ed775e 270 }
f3ed775e
DG
271 }
272
9f19cc17
DG
273 if (!chan_found && channel_name != NULL) {
274 MSG("Channel %s not found", channel_name);
275 }
f3ed775e 276
9f19cc17
DG
277end:
278 free(channels);
279 ret = CMD_SUCCESS;
f3ed775e
DG
280
281error:
282 return ret;
283}
284
285/*
9f19cc17 286 * List available tracing session. List only basic information.
f3ed775e 287 *
9f19cc17 288 * If session_name is NULL, all sessions are listed.
f3ed775e 289 */
9f19cc17 290static int list_sessions(const char *session_name)
f3ed775e 291{
9f19cc17
DG
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 }
cd80958d 315 continue;
9f19cc17
DG
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) {
6e0de39b 332 MSG("\nUse lttng list <session_name> for more details");
9f19cc17 333 }
f3ed775e
DG
334
335 return CMD_SUCCESS;
336
337error:
338 return ret;
339}
f3ed775e
DG
340
341/*
9f19cc17 342 * List available domain(s) for a session.
f3ed775e 343 */
cd80958d 344static int list_domains(void)
f3ed775e 345{
9f19cc17
DG
346 int i, count, ret = CMD_SUCCESS;
347 struct lttng_domain *domains = NULL;
348
349 MSG("Domains:\n-------------");
350
cd80958d 351 count = lttng_list_domains(handle, &domains);
9f19cc17
DG
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
369end:
370 free(domains);
371
372error:
373 return ret;
f3ed775e 374}
f3ed775e
DG
375
376/*
9f19cc17 377 * The 'list <options>' first level command
f3ed775e
DG
378 */
379int cmd_list(int argc, const char **argv)
380{
9f19cc17
DG
381 int opt, i, ret = CMD_SUCCESS;
382 const char *session_name;
f3ed775e 383 static poptContext pc;
9f19cc17
DG
384 struct lttng_domain domain;
385 struct lttng_domain *domains = NULL;
f3ed775e 386
9f19cc17 387 if (argc < 1) {
f3ed775e
DG
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;
f3ed775e
DG
400 default:
401 usage(stderr);
402 ret = CMD_UNDEFINED;
403 goto end;
404 }
405 }
406
9f19cc17
DG
407 if (opt_userspace || opt_pid != 0) {
408 MSG("*** Userspace tracing not implemented ***\n");
f3ed775e
DG
409 }
410
9f19cc17
DG
411 /* Get session name (trailing argument) */
412 session_name = poptGetArg(pc);
413 DBG("Session name: %s", session_name);
414
cd80958d
DG
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
9f19cc17
DG
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) {
cd80958d 445 ret = list_domains();
9f19cc17
DG
446 goto end;
447 }
448
449 if (opt_kernel) {
9f19cc17 450 /* Channel listing */
cd80958d 451 ret = list_channels(opt_channel);
9f19cc17
DG
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) */
cd80958d 459 ret = lttng_list_domains(handle, &domains);
9f19cc17
DG
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
cd80958d
DG
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);
9f19cc17
DG
483 if (ret < 0) {
484 goto end;
485 }
486 }
487 }
f3ed775e
DG
488 }
489
490end:
9f19cc17
DG
491 if (domains) {
492 free(domains);
493 }
cd80958d
DG
494 lttng_destroy_handle(handle);
495
f3ed775e
DG
496 return ret;
497}
This page took 0.046164 seconds and 5 git commands to generate.