Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng / commands / enable_events.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2011 EfficiOS Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8#define _LGPL_SOURCE
9#include <common/compat/getenv.hpp>
10#include <common/compat/string.hpp>
11#include <common/make-unique-wrapper.hpp>
12#include <common/scope-exit.hpp>
13#include <common/sessiond-comm/sessiond-comm.hpp>
14#include <common/string-utils/string-utils.hpp>
15#include <common/utils.hpp>
16
17#include <ctype.h>
18#include <inttypes.h>
19#include <popt.h>
20#include <sstream>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27#include <vector>
28
29/* Mi dependancy */
30#include "../command.hpp"
31#include "../loglevel.hpp"
32#include "../uprobe.hpp"
33
34#include <common/mi-lttng.hpp>
35
36#include <lttng/domain-internal.hpp>
37#include <lttng/event-internal.hpp>
38
39#if (LTTNG_SYMBOL_NAME_LEN == 256)
40#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
41#endif
42
43namespace {
44void _mi_lttng_writer_deleter_func(mi_writer *writer)
45{
46 if (writer && mi_lttng_writer_destroy(writer)) {
47 LTTNG_THROW_ERROR("Failed to destroy mi_writer instance");
48 }
49}
50
51using mi_writer_uptr = std::unique_ptr<
52 mi_writer,
53 lttng::memory::create_deleter_class<mi_writer, _mi_lttng_writer_deleter_func>::deleter>;
54using event_rule_patterns = std::vector<std::string>;
55
56int opt_event_type;
57const char *opt_loglevel;
58int opt_loglevel_type;
59int opt_kernel;
60char *opt_session_name;
61int opt_userspace;
62int opt_jul;
63int opt_log4j;
64int opt_log4j2;
65int opt_python;
66int opt_enable_all;
67char *opt_probe;
68char *opt_userspace_probe;
69char *opt_function;
70char *opt_channel_name;
71char *opt_filter;
72char *opt_exclude;
73
74struct lttng_handle *handle;
75mi_writer_uptr writer;
76
77#ifdef LTTNG_EMBED_HELP
78static const char help_msg[] =
79#include <lttng-enable-event.1.h>
80 ;
81#endif
82
83enum {
84 OPT_HELP = 1,
85 OPT_TRACEPOINT,
86 OPT_PROBE,
87 OPT_USERSPACE_PROBE,
88 OPT_FUNCTION,
89 OPT_SYSCALL,
90 OPT_USERSPACE,
91 OPT_LOGLEVEL,
92 OPT_LOGLEVEL_ONLY,
93 OPT_LIST_OPTIONS,
94 OPT_FILTER,
95 OPT_EXCLUDE,
96};
97
98struct poptOption long_options[] = {
99 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
100 { "help", 'h', POPT_ARG_NONE, nullptr, OPT_HELP, nullptr, nullptr },
101 { "session", 's', POPT_ARG_STRING, &opt_session_name, 0, nullptr, nullptr },
102 { "all", 'a', POPT_ARG_VAL, &opt_enable_all, 1, nullptr, nullptr },
103 { "channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, nullptr, nullptr },
104 { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, nullptr, nullptr },
105 { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr },
106 { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr },
107 { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr },
108 { "log4j2", 0, POPT_ARG_VAL, &opt_log4j2, 1, nullptr, nullptr },
109 { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr },
110 { "tracepoint", 0, POPT_ARG_NONE, nullptr, OPT_TRACEPOINT, nullptr, nullptr },
111 { "probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, nullptr, nullptr },
112 { "userspace-probe",
113 0,
114 POPT_ARG_STRING,
115 &opt_userspace_probe,
116 OPT_USERSPACE_PROBE,
117 nullptr,
118 nullptr },
119 { "function", 0, POPT_ARG_STRING, &opt_function, OPT_FUNCTION, nullptr, nullptr },
120 { "syscall", 0, POPT_ARG_NONE, nullptr, OPT_SYSCALL, nullptr, nullptr },
121 { "loglevel", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL, nullptr, nullptr },
122 { "loglevel-only", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL_ONLY, nullptr, nullptr },
123 { "list-options", 0, POPT_ARG_NONE, nullptr, OPT_LIST_OPTIONS, nullptr, nullptr },
124 { "filter", 'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, nullptr, nullptr },
125 { "exclude", 'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, nullptr, nullptr },
126 { nullptr, 0, 0, nullptr, 0, nullptr, nullptr }
127};
128
129/*
130 * Parse probe options.
131 */
132int parse_probe_opts(struct lttng_event *ev, char *opt)
133{
134 int ret = CMD_SUCCESS;
135 int match;
136 char s_hex[19];
137#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */
138 char name[LTTNG_SYMBOL_NAME_LEN];
139
140 if (opt == nullptr) {
141 ret = CMD_ERROR;
142 goto end;
143 }
144
145 /* Check for symbol+offset */
146 match = sscanf(opt,
147 "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
148 "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s",
149 name,
150 s_hex);
151 if (match == 2) {
152 strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
153 ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
154 DBG("probe symbol %s", ev->attr.probe.symbol_name);
155 if (*s_hex == '\0') {
156 ERR("Invalid probe offset %s", s_hex);
157 ret = CMD_ERROR;
158 goto end;
159 }
160 ev->attr.probe.offset = strtoull(s_hex, nullptr, 0);
161 DBG("probe offset %" PRIu64, ev->attr.probe.offset);
162 ev->attr.probe.addr = 0;
163 goto end;
164 }
165
166 /* Check for symbol */
167 if (isalpha(name[0]) || name[0] == '_') {
168 match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", name);
169 if (match == 1) {
170 strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
171 ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
172 DBG("probe symbol %s", ev->attr.probe.symbol_name);
173 ev->attr.probe.offset = 0;
174 DBG("probe offset %" PRIu64, ev->attr.probe.offset);
175 ev->attr.probe.addr = 0;
176 goto end;
177 }
178 }
179
180 /* Check for address */
181 match = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex);
182 if (match > 0) {
183 /*
184 * Return an error if the first character of the tentative
185 * address is NULL or not a digit. It can be "0" if the address
186 * is in hexadecimal and can be 1 to 9 if it's in decimal.
187 */
188 if (*s_hex == '\0' || !isdigit(*s_hex)) {
189 ERR("Invalid probe description `%s`", s_hex);
190 ret = CMD_ERROR;
191 goto end;
192 }
193 ev->attr.probe.addr = strtoull(s_hex, nullptr, 0);
194 DBG("probe addr %" PRIu64, ev->attr.probe.addr);
195 ev->attr.probe.offset = 0;
196 memset(ev->attr.probe.symbol_name, 0, LTTNG_SYMBOL_NAME_LEN);
197 goto end;
198 }
199
200 /* No match */
201 ret = CMD_ERROR;
202
203end:
204 return ret;
205}
206
207const char *print_channel_name(const char *name)
208{
209 return name ?: DEFAULT_CHANNEL_NAME;
210}
211
212const char *print_raw_channel_name(const char *name)
213{
214 return name ?: "<default>";
215}
216
217/*
218 * Mi print exlcusion list
219 */
220int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
221{
222 int ret;
223 size_t i;
224 const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
225
226 LTTNG_ASSERT(writer);
227
228 if (count == 0) {
229 ret = 0;
230 goto end;
231 }
232
233 ret = mi_lttng_writer_open_element(writer.get(), config_element_exclusions);
234 if (ret) {
235 goto end;
236 }
237
238 for (i = 0; i < count; i++) {
239 const char *exclusion =
240 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
241
242 ret = mi_lttng_writer_write_element_string(
243 writer.get(), config_element_exclusion, exclusion);
244 if (ret) {
245 goto end;
246 }
247 }
248
249 /* Close exclusions element */
250 ret = mi_lttng_writer_close_element(writer.get());
251
252end:
253 return ret;
254}
255
256/*
257 * Return allocated string for pretty-printing exclusion names.
258 */
259char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
260{
261 int length = 0;
262 size_t i;
263 const char preamble[] = " excluding ";
264 char *ret;
265 const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
266
267 if (count == 0) {
268 return strdup("");
269 }
270
271 /* Calculate total required length. */
272 for (i = 0; i < count; i++) {
273 const char *exclusion =
274 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
275
276 length += strlen(exclusion) + 4;
277 }
278
279 length += sizeof(preamble);
280 ret = calloc<char>(length);
281 if (!ret) {
282 return nullptr;
283 }
284
285 strncpy(ret, preamble, length);
286 for (i = 0; i < count; i++) {
287 const char *exclusion =
288 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
289
290 strcat(ret, "`");
291 strcat(ret, exclusion);
292 strcat(ret, "`");
293 if (i != count - 1) {
294 strcat(ret, ", ");
295 }
296 }
297
298 return ret;
299}
300
301int check_exclusion_subsets(const char *pattern, const char *exclusion)
302{
303 bool warn = false;
304 int ret = 0;
305 const char *e = pattern;
306 const char *x = exclusion;
307
308 /* Scan both the excluder and the event letter by letter */
309 while (true) {
310 if (*e == '\\') {
311 if (*x != *e) {
312 warn = true;
313 goto end;
314 }
315
316 e++;
317 x++;
318 goto cmp_chars;
319 }
320
321 if (*x == '*') {
322 /* Event is a subset of the excluder */
323 ERR("Exclusion pattern `%s` excludes all events from `%s`",
324 exclusion,
325 pattern);
326 goto error;
327 }
328
329 if (*e == '*') {
330 /*
331 * Reached the end of the event name before the
332 * end of the exclusion: this is valid.
333 */
334 goto end;
335 }
336
337 cmp_chars:
338 if (*x != *e) {
339 warn = true;
340 break;
341 }
342
343 x++;
344 e++;
345 }
346
347 goto end;
348
349error:
350 ret = -1;
351
352end:
353 if (warn) {
354 WARN("Exclusion pattern `%s` does not exclude any event from `%s`",
355 exclusion,
356 pattern);
357 }
358
359 return ret;
360}
361
362int create_exclusion_list_and_validate(const char *pattern,
363 const char *exclusions_arg,
364 struct lttng_dynamic_pointer_array *exclusions)
365{
366 int ret = 0;
367
368 /* Split exclusions. */
369 ret = strutils_split(exclusions_arg, ',', true, exclusions);
370 if (ret < 0) {
371 goto error;
372 }
373
374 if (validate_exclusion_list(pattern, exclusions) != 0) {
375 goto error;
376 }
377
378 goto end;
379
380error:
381 ret = -1;
382 lttng_dynamic_pointer_array_reset(exclusions);
383
384end:
385 return ret;
386}
387
388void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions,
389 int *warn)
390{
391 size_t i;
392 const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
393
394 for (i = 0; i < num_exclusions; i++) {
395 const char *const exclusion =
396 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
397
398 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
399 WARN("Event exclusion \"%s\" will be truncated", exclusion);
400 *warn = 1;
401 }
402 }
403}
404
405/*
406 * Enabling event using the lttng API.
407 * Note: in case of error only the last error code will be return.
408 */
409int enable_events(const std::string& session_name, const event_rule_patterns& patterns)
410{
411 int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
412 int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1;
413 char *channel_name = nullptr;
414 struct lttng_event *ev;
415 struct lttng_domain dom = {};
416 struct lttng_dynamic_pointer_array exclusions;
417 struct lttng_userspace_probe_location *uprobe_loc = nullptr;
418
419 lttng_dynamic_pointer_array_init(&exclusions, nullptr);
420
421 ev = lttng_event_create();
422 if (!ev) {
423 ret = CMD_ERROR;
424 goto error;
425 }
426
427 if (opt_kernel) {
428 if (opt_loglevel) {
429 WARN("Kernel log levels are not supported");
430 }
431 }
432
433 /* Create lttng domain */
434 if (opt_kernel) {
435 dom.type = LTTNG_DOMAIN_KERNEL;
436 dom.buf_type = LTTNG_BUFFER_GLOBAL;
437 } else if (opt_userspace) {
438 dom.type = LTTNG_DOMAIN_UST;
439 /* Default. */
440 dom.buf_type = LTTNG_BUFFER_PER_UID;
441 } else if (opt_jul) {
442 dom.type = LTTNG_DOMAIN_JUL;
443 /* Default. */
444 dom.buf_type = LTTNG_BUFFER_PER_UID;
445 } else if (opt_log4j) {
446 dom.type = LTTNG_DOMAIN_LOG4J;
447 /* Default. */
448 dom.buf_type = LTTNG_BUFFER_PER_UID;
449 } else if (opt_log4j2) {
450 dom.type = LTTNG_DOMAIN_LOG4J2;
451 /* Default. */
452 dom.buf_type = LTTNG_BUFFER_PER_UID;
453 } else if (opt_python) {
454 dom.type = LTTNG_DOMAIN_PYTHON;
455 /* Default. */
456 dom.buf_type = LTTNG_BUFFER_PER_UID;
457 } else {
458 /* Checked by the caller. */
459 abort();
460 }
461
462 if (opt_exclude) {
463 switch (dom.type) {
464 case LTTNG_DOMAIN_KERNEL:
465 case LTTNG_DOMAIN_JUL:
466 case LTTNG_DOMAIN_LOG4J:
467 case LTTNG_DOMAIN_LOG4J2:
468 case LTTNG_DOMAIN_PYTHON:
469 ERR("Event name exclusions are not supported for %s event rules",
470 lttng_domain_type_str(dom.type));
471 ret = CMD_ERROR;
472 goto error;
473 case LTTNG_DOMAIN_UST:
474 /* Exclusions supported */
475 break;
476 default:
477 abort();
478 }
479 }
480
481 /*
482 * Adding a filter to a probe, function or userspace-probe would be
483 * denied by the kernel tracer as it's not supported at the moment. We
484 * do an early check here to warn the user.
485 */
486 if (opt_filter && opt_kernel) {
487 switch (opt_event_type) {
488 case LTTNG_EVENT_ALL:
489 case LTTNG_EVENT_TRACEPOINT:
490 case LTTNG_EVENT_SYSCALL:
491 break;
492 case LTTNG_EVENT_PROBE:
493 case LTTNG_EVENT_USERSPACE_PROBE:
494 case LTTNG_EVENT_FUNCTION:
495 ERR("Filter expressions are not supported for %s event rules",
496 get_event_type_str((lttng_event_type) opt_event_type));
497 ret = CMD_ERROR;
498 goto error;
499 default:
500 ret = CMD_UNDEFINED;
501 goto error;
502 }
503 }
504
505 channel_name = opt_channel_name;
506
507 handle = lttng_create_handle(session_name.c_str(), &dom);
508 if (handle == nullptr) {
509 ret = -1;
510 goto error;
511 }
512
513 /* Prepare Mi */
514 if (lttng_opt_mi) {
515 /* Open a events element */
516 ret = mi_lttng_writer_open_element(writer.get(), config_element_events);
517 if (ret) {
518 ret = CMD_ERROR;
519 goto error;
520 }
521 }
522
523 for (const auto& pattern : patterns) {
524 /* Copy name and type of the event */
525 strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN);
526 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
527 ev->type = (lttng_event_type) opt_event_type;
528
529 /* Kernel tracer action */
530 if (opt_kernel) {
531 DBG_FMT("Enabling kernel event rule: pattern=`{}`, channel_name=`{}`",
532 pattern,
533 print_channel_name(channel_name));
534
535 switch (opt_event_type) {
536 case LTTNG_EVENT_ALL: /* Enable tracepoints and syscalls */
537 /* If event name differs from *, select tracepoint. */
538 if (strcmp(ev->name, "*") != 0) {
539 ev->type = LTTNG_EVENT_TRACEPOINT;
540 }
541 break;
542 case LTTNG_EVENT_TRACEPOINT:
543 break;
544 case LTTNG_EVENT_PROBE:
545 ret = parse_probe_opts(ev, opt_probe);
546 if (ret) {
547 ERR("Unable to parse probe options");
548 ret = CMD_ERROR;
549 goto error;
550 }
551 break;
552 case LTTNG_EVENT_USERSPACE_PROBE:
553 LTTNG_ASSERT(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
554
555 ret = parse_userspace_probe_opts(opt_userspace_probe, &uprobe_loc);
556 if (ret) {
557 switch (ret) {
558 case CMD_UNSUPPORTED:
559 /*
560 * Error message describing
561 * what is not supported was
562 * printed in the function.
563 */
564 break;
565 case CMD_ERROR:
566 default:
567 ERR("Unable to parse user space probe options");
568 break;
569 }
570 goto error;
571 }
572
573 ret = lttng_event_set_userspace_probe_location(ev, uprobe_loc);
574 if (ret) {
575 WARN("Failed to set probe location on event");
576 ret = CMD_ERROR;
577 goto error;
578 }
579
580 /* Ownership of the uprobe location was transferred to the event. */
581 uprobe_loc = nullptr;
582 break;
583 case LTTNG_EVENT_FUNCTION:
584 ret = parse_probe_opts(ev, opt_function);
585 if (ret) {
586 ERR("Unable to parse function probe options");
587 ret = CMD_ERROR;
588 goto error;
589 }
590 break;
591 case LTTNG_EVENT_SYSCALL:
592 ev->type = LTTNG_EVENT_SYSCALL;
593 break;
594 default:
595 ret = CMD_UNDEFINED;
596 goto error;
597 }
598
599 /* kernel loglevels not implemented */
600 ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
601 } else if (opt_userspace) { /* User-space tracer action */
602 DBG_FMT("Enabling user space event rule: pattern=`{}`, channel_name=`{}`, log_level=`{}`",
603 pattern.c_str(),
604 print_channel_name(channel_name),
605 opt_loglevel ?: "all");
606
607 switch (opt_event_type) {
608 case LTTNG_EVENT_ALL: /* Default behavior is tracepoint */
609 /* Fall-through */
610 case LTTNG_EVENT_TRACEPOINT:
611 /* Copy name and type of the event */
612 ev->type = LTTNG_EVENT_TRACEPOINT;
613 strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN);
614 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
615 break;
616 case LTTNG_EVENT_PROBE:
617 case LTTNG_EVENT_FUNCTION:
618 case LTTNG_EVENT_SYSCALL:
619 case LTTNG_EVENT_USERSPACE_PROBE:
620 default:
621 ERR("Instrumentation point type not supported for the %s domain",
622 lttng_domain_type_str(dom.type));
623 ret = CMD_UNSUPPORTED;
624 goto error;
625 }
626
627 if (opt_exclude) {
628 ev->exclusion = 1;
629 if (opt_event_type != LTTNG_EVENT_ALL &&
630 opt_event_type != LTTNG_EVENT_TRACEPOINT) {
631 ERR("Exclusion option can only be used with tracepoint events");
632 ret = CMD_ERROR;
633 goto error;
634 }
635 /* Free previously allocated items. */
636 lttng_dynamic_pointer_array_reset(&exclusions);
637 ret = create_exclusion_list_and_validate(
638 pattern.c_str(), opt_exclude, &exclusions);
639 if (ret) {
640 ret = CMD_ERROR;
641 goto error;
642 }
643
644 warn_on_truncated_exclusion_names(&exclusions, &warn);
645 }
646
647 ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
648 if (opt_loglevel) {
649 enum lttng_loglevel loglevel;
650 const int name_search_ret =
651 loglevel_name_to_value(opt_loglevel, &loglevel);
652
653 if (name_search_ret == -1) {
654 ERR("Unknown log level `%s`", opt_loglevel);
655 ret = -LTTNG_ERR_INVALID;
656 goto error;
657 }
658
659 ev->loglevel = (int) loglevel;
660 } else {
661 ev->loglevel = -1;
662 }
663 } else if (opt_jul || opt_log4j || opt_log4j2 || opt_python) {
664 if (opt_event_type != LTTNG_EVENT_ALL &&
665 opt_event_type != LTTNG_EVENT_TRACEPOINT) {
666 ERR("Instrumentation point type not supported for the %s domain",
667 lttng_domain_type_str(dom.type));
668 ret = CMD_UNSUPPORTED;
669 goto error;
670 }
671
672 ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
673 if (opt_loglevel) {
674 int name_search_ret;
675
676 if (opt_jul) {
677 enum lttng_loglevel_jul loglevel;
678
679 name_search_ret =
680 loglevel_jul_name_to_value(opt_loglevel, &loglevel);
681 ev->loglevel = (int) loglevel;
682 } else if (opt_log4j) {
683 enum lttng_loglevel_log4j loglevel;
684
685 name_search_ret = loglevel_log4j_name_to_value(opt_loglevel,
686 &loglevel);
687 ev->loglevel = (int) loglevel;
688 } else if (opt_log4j2) {
689 enum lttng_loglevel_log4j2 loglevel;
690
691 name_search_ret = loglevel_log4j2_name_to_value(
692 opt_loglevel, &loglevel);
693 ev->loglevel = (int) loglevel;
694 } else {
695 /* python domain. */
696 enum lttng_loglevel_python loglevel;
697
698 name_search_ret = loglevel_python_name_to_value(
699 opt_loglevel, &loglevel);
700 ev->loglevel = (int) loglevel;
701 }
702
703 if (name_search_ret) {
704 ERR("Unknown log level `%s`", opt_loglevel);
705 ret = -LTTNG_ERR_INVALID;
706 goto error;
707 }
708 } else {
709 if (opt_jul) {
710 ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
711 } else if (opt_log4j) {
712 ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
713 } else if (opt_log4j2) {
714 ev->loglevel = LTTNG_LOGLEVEL_LOG4J2_ALL;
715 } else if (opt_python) {
716 ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
717 }
718 }
719 ev->type = LTTNG_EVENT_TRACEPOINT;
720 strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN);
721 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
722 } else {
723 abort();
724 }
725
726 if (!opt_filter) {
727 command_ret = lttng_enable_event_with_exclusions(
728 handle,
729 ev,
730 channel_name,
731 nullptr,
732 lttng_dynamic_pointer_array_get_count(&exclusions),
733 (char **) exclusions.array.buffer.data);
734
735 auto exclusion_string =
736 lttng::make_unique_wrapper<char, lttng::memory::free>(
737 print_exclusions(&exclusions));
738 if (!exclusion_string) {
739 PERROR("Cannot allocate exclusion_string");
740 error = 1;
741 goto end;
742 }
743
744 if (command_ret < 0) {
745 /* Turn ret to positive value to handle the positive error code */
746 switch (-command_ret) {
747 case LTTNG_ERR_KERN_EVENT_EXIST:
748 WARN("Kernel event rule %s%s and attached to channel `%s` is already enabled (session `%s`)",
749 opt_enable_all ? "matching all events" :
750 (std::string("with pattern `") +
751 pattern + std::string("`"))
752 .c_str(),
753 exclusion_string.get(),
754 print_channel_name(channel_name),
755 session_name.c_str());
756 warn = 1;
757 break;
758 case LTTNG_ERR_TRACE_ALREADY_STARTED:
759 {
760 ERR("Can't enable an event in a new domain for a session that has already been started once (session `%s`)",
761 session_name.c_str());
762 error = 1;
763 break;
764 }
765 case LTTNG_ERR_SDT_PROBE_SEMAPHORE:
766 ERR("Failed to enable event rule with pattern `%s` and attached to channel `%s` as SDT probes guarded by semaphores are not supported (session `%s`)",
767 pattern.c_str(),
768 print_channel_name(channel_name),
769 session_name.c_str());
770 error = 1;
771 break;
772 default:
773 ERR("Failed to enable event rule %s%s and attached to channel `%s`: %s (session `%s`)",
774 opt_enable_all ? "matching all events" :
775 (std::string("with pattern `") +
776 pattern + std::string("`"))
777 .c_str(),
778 exclusion_string.get(),
779 command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
780 print_raw_channel_name(channel_name) :
781 print_channel_name(channel_name),
782 lttng_strerror(command_ret),
783 session_name.c_str());
784
785 if (opt_kernel) {
786 print_kernel_tracer_status_error();
787 }
788
789 error = 1;
790 break;
791 }
792 error_holder = command_ret;
793 } else {
794 switch (dom.type) {
795 case LTTNG_DOMAIN_KERNEL:
796 case LTTNG_DOMAIN_UST:
797 {
798 MSG("Enabled %s event rule %s%s and attached to channel `%s`",
799 lttng_domain_type_str(dom.type),
800 opt_enable_all ? "matching all events" :
801 (std::string("with pattern `") +
802 pattern + std::string("`"))
803 .c_str(),
804 exclusion_string.get(),
805 print_channel_name(channel_name));
806 break;
807 }
808 case LTTNG_DOMAIN_JUL:
809 case LTTNG_DOMAIN_LOG4J:
810 case LTTNG_DOMAIN_LOG4J2:
811 case LTTNG_DOMAIN_PYTHON:
812 /*
813 * Don't print the default channel
814 * name for agent domains.
815 */
816 MSG("Enabled %s event rule %s%s",
817 lttng_domain_type_str(dom.type),
818 opt_enable_all ? "matching all events" :
819 (std::string("with pattern `") +
820 pattern + std::string("`"))
821 .c_str(),
822 exclusion_string.get());
823 break;
824 default:
825 abort();
826 }
827 }
828 } else {
829 /* Filter present */
830 ev->filter = 1;
831
832 command_ret = lttng_enable_event_with_exclusions(
833 handle,
834 ev,
835 channel_name,
836 opt_filter,
837 lttng_dynamic_pointer_array_get_count(&exclusions),
838 (char **) exclusions.array.buffer.data);
839
840 auto exclusion_string =
841 lttng::make_unique_wrapper<char, lttng::memory::free>(
842 print_exclusions(&exclusions));
843 if (!exclusion_string) {
844 PERROR("Failed allocate exclusion string");
845 error = 1;
846 goto end;
847 }
848 if (command_ret < 0) {
849 switch (-command_ret) {
850 case LTTNG_ERR_FILTER_EXIST:
851 WARN("An event rule %s%s and filter expression `%s` is already attached to channel `%s`",
852 opt_enable_all ? "matching all events" :
853 (std::string("with pattern `") +
854 pattern + std::string("`"))
855 .c_str(),
856 exclusion_string.get(),
857 opt_filter,
858 print_channel_name(channel_name));
859 warn = 1;
860 break;
861 case LTTNG_ERR_TRACE_ALREADY_STARTED:
862 {
863 ERR("Can't enable an event in a new domain for a session that has already been started once (session `%s`)",
864 session_name.c_str());
865 error = 1;
866 break;
867 }
868 default:
869 ERR("Failed to enable event rule %s%s, with filter expression `%s`, and attached to channel `%s`: %s (session `%s`)",
870 opt_enable_all ? "matching all events" :
871 (std::string("with pattern `") +
872 pattern + std::string("`"))
873 .c_str(),
874 exclusion_string.get(),
875 opt_filter,
876 command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
877 print_raw_channel_name(channel_name) :
878 print_channel_name(channel_name),
879 lttng_strerror(command_ret),
880 session_name.c_str());
881 error = 1;
882
883 if (opt_kernel) {
884 print_kernel_tracer_status_error();
885 }
886
887 break;
888 }
889
890 error_holder = command_ret;
891 } else {
892 MSG("Enabled %s event rule %s%s and filter expression `%s`",
893 lttng_domain_type_str(dom.type),
894 opt_enable_all ? "matching all events" :
895 (std::string("with pattern `") + pattern +
896 std::string("`"))
897 .c_str(),
898
899 exclusion_string.get(),
900 opt_filter);
901 }
902 }
903
904 if (lttng_opt_mi) {
905 if (command_ret) {
906 success = 0;
907 ev->enabled = 0;
908 } else {
909 ev->enabled = 1;
910 }
911
912 ret = mi_lttng_event(writer.get(), ev, 1, handle->domain.type);
913 if (ret) {
914 ret = CMD_ERROR;
915 goto error;
916 }
917
918 /* print exclusion */
919 ret = mi_print_exclusion(&exclusions);
920 if (ret) {
921 ret = CMD_ERROR;
922 goto error;
923 }
924
925 /* Success ? */
926 ret = mi_lttng_writer_write_element_bool(
927 writer.get(), mi_lttng_element_command_success, success);
928 if (ret) {
929 ret = CMD_ERROR;
930 goto end;
931 }
932
933 /* Close event element */
934 ret = mi_lttng_writer_close_element(writer.get());
935 if (ret) {
936 ret = CMD_ERROR;
937 goto end;
938 }
939 }
940
941 /* Reset warn, error and success */
942 success = 1;
943 }
944
945end:
946 /* Close Mi */
947 if (lttng_opt_mi) {
948 /* Close events element */
949 ret = mi_lttng_writer_close_element(writer.get());
950 if (ret) {
951 ret = CMD_ERROR;
952 goto error;
953 }
954 }
955error:
956 if (warn) {
957 ret = CMD_WARNING;
958 }
959 if (error) {
960 ret = CMD_ERROR;
961 }
962 lttng_destroy_handle(handle);
963 lttng_dynamic_pointer_array_reset(&exclusions);
964 lttng_userspace_probe_location_destroy(uprobe_loc);
965
966 /* Overwrite ret with error_holder if there was an actual error with
967 * enabling an event.
968 */
969 ret = error_holder ? error_holder : ret;
970
971 lttng_event_destroy(ev);
972 return ret;
973}
974
975void _poptContextFree_deleter_func(poptContext ctx)
976{
977 poptFreeContext(ctx);
978}
979
980} /* namespace */
981
982int validate_exclusion_list(const char *pattern,
983 const struct lttng_dynamic_pointer_array *exclusions)
984{
985 int ret;
986
987 /* Event name pattern must be a valid globbing pattern to allow exclusions. */
988 if (!strutils_is_star_glob_pattern(pattern)) {
989 ERR("Event name pattern must contain wildcard characters to use exclusions");
990 goto error;
991 }
992
993 /*
994 * If the event name is a star-at-end only globbing pattern,
995 * then we can validate the individual exclusions. Otherwise
996 * all exclusions are passed to the session daemon.
997 */
998 if (strutils_is_star_at_the_end_only_glob_pattern(pattern)) {
999 size_t i, num_exclusions;
1000
1001 num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
1002
1003 for (i = 0; i < num_exclusions; i++) {
1004 const char *exclusion =
1005 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions,
1006 i);
1007
1008 if (!strutils_is_star_glob_pattern(exclusion) ||
1009 strutils_is_star_at_the_end_only_glob_pattern(exclusion)) {
1010 ret = check_exclusion_subsets(pattern, exclusion);
1011 if (ret) {
1012 goto error;
1013 }
1014 }
1015 }
1016 }
1017
1018 ret = 0;
1019 goto end;
1020
1021error:
1022 ret = -1;
1023
1024end:
1025 return ret;
1026}
1027
1028/*
1029 * Add event to trace session
1030 */
1031int cmd_enable_events(int argc, const char **argv)
1032{
1033 int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
1034 std::string session_name;
1035 const char *arg_event_list = nullptr;
1036 const char *leftover = nullptr;
1037 int event_type = -1;
1038 event_rule_patterns patterns;
1039
1040 auto pc = lttng::make_unique_wrapper<poptContext_s, _poptContextFree_deleter_func>(
1041 poptGetContext(nullptr, argc, argv, long_options, 0));
1042 poptReadDefaultConfig(pc.get(), 0);
1043
1044 /* Default event type */
1045 opt_event_type = LTTNG_EVENT_ALL;
1046
1047 while ((opt = poptGetNextOpt(pc.get())) != -1) {
1048 switch (opt) {
1049 case OPT_HELP:
1050 SHOW_HELP();
1051 return CMD_SUCCESS;
1052 case OPT_TRACEPOINT:
1053 opt_event_type = LTTNG_EVENT_TRACEPOINT;
1054 break;
1055 case OPT_PROBE:
1056 opt_event_type = LTTNG_EVENT_PROBE;
1057 break;
1058 case OPT_USERSPACE_PROBE:
1059 opt_event_type = LTTNG_EVENT_USERSPACE_PROBE;
1060 break;
1061 case OPT_FUNCTION:
1062 opt_event_type = LTTNG_EVENT_FUNCTION;
1063 break;
1064 case OPT_SYSCALL:
1065 opt_event_type = LTTNG_EVENT_SYSCALL;
1066 break;
1067 case OPT_USERSPACE:
1068 opt_userspace = 1;
1069 break;
1070 case OPT_LOGLEVEL:
1071 opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
1072 opt_loglevel = poptGetOptArg(pc.get());
1073 break;
1074 case OPT_LOGLEVEL_ONLY:
1075 opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
1076 opt_loglevel = poptGetOptArg(pc.get());
1077 break;
1078 case OPT_LIST_OPTIONS:
1079 list_cmd_options(stdout, long_options);
1080 return CMD_SUCCESS;
1081 case OPT_FILTER:
1082 break;
1083 case OPT_EXCLUDE:
1084 break;
1085 default:
1086 return CMD_UNDEFINED;
1087 }
1088
1089 /* Validate event type. Multiple event type are not supported. */
1090 if (event_type == -1) {
1091 event_type = opt_event_type;
1092 } else {
1093 if (event_type != opt_event_type) {
1094 ERR("Only one event type may be enabled at once");
1095 return CMD_ERROR;
1096 }
1097 }
1098 }
1099
1100 ret = print_missing_or_multiple_domains(
1101 opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_log4j2 + opt_python, true);
1102 if (ret) {
1103 return CMD_ERROR;
1104 }
1105
1106 /* Mi check */
1107 if (lttng_opt_mi) {
1108 writer = mi_writer_uptr(mi_lttng_writer_create(fileno(stdout), lttng_opt_mi));
1109 if (!writer) {
1110 LTTNG_THROW_ERROR(lttng::format(
1111 "Failed to create MI writer: format_code={}", lttng_opt_mi));
1112 }
1113
1114 /* Open command element */
1115 ret = mi_lttng_writer_command_open(writer.get(),
1116 mi_lttng_element_command_enable_event);
1117 if (ret) {
1118 LTTNG_THROW_ERROR(lttng::format(
1119 "Failed to open MI command element: command_name=`{}`",
1120 mi_lttng_element_command_enable_event));
1121 }
1122
1123 /* Open output element */
1124 ret = mi_lttng_writer_open_element(writer.get(), mi_lttng_element_command_output);
1125 if (ret) {
1126 LTTNG_THROW_ERROR(
1127 lttng::format("Failed to open MI element: element_name=`{}`",
1128 mi_lttng_element_command_output));
1129 }
1130 }
1131
1132 /* Close the MI command context when leaving the function, no matter the result. */
1133 const auto close_mi_on_exit = lttng::make_scope_exit([&success]() noexcept {
1134 if (!lttng_opt_mi) {
1135 return;
1136 }
1137
1138 /* Close output element. */
1139 if (mi_lttng_writer_close_element(writer.get())) {
1140 ERR_FMT("Failed to close MI output element");
1141 return;
1142 }
1143
1144 if (mi_lttng_writer_write_element_bool(
1145 writer.get(), mi_lttng_element_command_success, success)) {
1146 ERR_FMT("Failed to write MI element: element_name=`{}`, value={}",
1147 mi_lttng_element_command_success,
1148 success);
1149 return;
1150 }
1151
1152 /* Command element close. */
1153 if (mi_lttng_writer_command_close(writer.get())) {
1154 ERR_FMT("Failed to close MI command element");
1155 return;
1156 }
1157 });
1158
1159 arg_event_list = poptGetArg(pc.get());
1160 if (arg_event_list == nullptr && opt_enable_all == 0) {
1161 ERR("Missing event name pattern(s)");
1162 return CMD_ERROR;
1163 }
1164
1165 if (opt_enable_all) {
1166 patterns.emplace_back("*");
1167 } else {
1168 std::stringstream event_list_arg_stream(arg_event_list);
1169
1170 for (std::string line; std::getline(event_list_arg_stream, line, ',');) {
1171 patterns.emplace_back(std::move(line));
1172 }
1173 }
1174
1175 leftover = poptGetArg(pc.get());
1176 if (leftover) {
1177 ERR("Unknown argument: %s", leftover);
1178 return CMD_ERROR;
1179 }
1180
1181 if (!opt_session_name) {
1182 const auto rc_file_session_name =
1183 lttng::make_unique_wrapper<char, lttng::memory::free>(get_session_name());
1184
1185 if (!rc_file_session_name) {
1186 return CMD_ERROR;
1187 }
1188
1189 session_name = rc_file_session_name.get();
1190 } else {
1191 session_name = opt_session_name;
1192 }
1193
1194 command_ret = enable_events(session_name, patterns);
1195 if (command_ret) {
1196 return CMD_ERROR;
1197 }
1198
1199 return CMD_SUCCESS;
1200}
This page took 0.02945 seconds and 5 git commands to generate.