SoW-2020-0002: Trace Hit Counters: trigger error reporting integration
[lttng-tools.git] / src / common / event-rule / tracepoint.c
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/payload.h>
12 #include <common/payload-view.h>
13 #include <common/runas.h>
14 #include <lttng/event-rule/event-rule-internal.h>
15 #include <lttng/event-rule/tracepoint-internal.h>
16 #include <lttng/event.h>
17
18 #define IS_TRACEPOINT_EVENT_RULE(rule) \
19 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_TRACEPOINT)
20
21 static void lttng_event_rule_tracepoint_destroy(struct lttng_event_rule *rule)
22 {
23 struct lttng_event_rule_tracepoint *tracepoint;
24
25 if (rule == NULL) {
26 return;
27 }
28
29 tracepoint = container_of(
30 rule, struct lttng_event_rule_tracepoint, parent);
31
32 lttng_dynamic_pointer_array_reset(&tracepoint->exclusions);
33 free(tracepoint->pattern);
34 free(tracepoint->filter_expression);
35 free(tracepoint->internal_filter.filter);
36 free(tracepoint->internal_filter.bytecode);
37 free(tracepoint);
38 }
39
40 static bool lttng_event_rule_tracepoint_validate(
41 const struct lttng_event_rule *rule)
42 {
43 bool valid = false;
44 struct lttng_event_rule_tracepoint *tracepoint;
45
46 if (!rule) {
47 goto end;
48 }
49
50 tracepoint = container_of(
51 rule, struct lttng_event_rule_tracepoint, parent);
52
53 /* Required field. */
54 if (!tracepoint->pattern) {
55 ERR("Invalid tracepoint event rule: a pattern must be set.");
56 goto end;
57 }
58
59 /* Required field. */
60 if (tracepoint->domain == LTTNG_DOMAIN_NONE) {
61 ERR("Invalid tracepoint event rule: a domain must be set.");
62 goto end;
63 }
64
65 valid = true;
66 end:
67 return valid;
68 }
69
70 static int lttng_event_rule_tracepoint_serialize(
71 const struct lttng_event_rule *rule,
72 struct lttng_payload *payload)
73 {
74 int ret, i;
75 size_t pattern_len, filter_expression_len, exclusions_len;
76 struct lttng_event_rule_tracepoint *tracepoint;
77 struct lttng_event_rule_tracepoint_comm tracepoint_comm;
78 enum lttng_event_rule_status status;
79 unsigned int exclusion_count;
80 size_t exclusions_appended_len = 0;
81
82 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
83 ret = -1;
84 goto end;
85 }
86
87 DBG("Serializing tracepoint event rule.");
88 tracepoint = container_of(
89 rule, struct lttng_event_rule_tracepoint, parent);
90
91 status = lttng_event_rule_tracepoint_get_exclusions_count(rule, &exclusion_count);
92 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
93
94 pattern_len = strlen(tracepoint->pattern) + 1;
95
96 if (tracepoint->filter_expression != NULL) {
97 filter_expression_len =
98 strlen(tracepoint->filter_expression) + 1;
99 } else {
100 filter_expression_len = 0;
101 }
102
103 exclusions_len = 0;
104 for (i = 0; i < exclusion_count; i++) {
105 const char *exclusion;
106
107 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
108 rule, i, &exclusion);
109 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
110
111 /* Length field. */
112 exclusions_len += sizeof(uint32_t);
113 /* Payload (null terminated). */
114 exclusions_len += strlen(exclusion) + 1;
115 }
116
117 tracepoint_comm.domain_type = (int8_t) tracepoint->domain;
118 tracepoint_comm.loglevel_type = (int8_t) tracepoint->loglevel.type;
119 tracepoint_comm.loglevel_value = tracepoint->loglevel.value;
120 tracepoint_comm.pattern_len = pattern_len;
121 tracepoint_comm.filter_expression_len = filter_expression_len;
122 tracepoint_comm.exclusions_count = exclusion_count;
123 tracepoint_comm.exclusions_len = exclusions_len;
124
125 ret = lttng_dynamic_buffer_append(&payload->buffer, &tracepoint_comm,
126 sizeof(tracepoint_comm));
127 if (ret) {
128 goto end;
129 }
130
131 ret = lttng_dynamic_buffer_append(
132 &payload->buffer, tracepoint->pattern, pattern_len);
133 if (ret) {
134 goto end;
135 }
136
137 ret = lttng_dynamic_buffer_append(&payload->buffer, tracepoint->filter_expression,
138 filter_expression_len);
139 if (ret) {
140 goto end;
141 }
142
143 for (i = 0; i < exclusion_count; i++) {
144 size_t len;
145 const char *exclusion;
146
147 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
148 rule, i, &exclusion);
149 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
150
151 len = strlen(exclusion) + 1;
152 /* Append exclusion length, includes the null terminator. */
153 ret = lttng_dynamic_buffer_append(
154 &payload->buffer, &len, sizeof(uint32_t));
155 if (ret) {
156 goto end;
157 }
158
159 exclusions_appended_len += sizeof(uint32_t);
160
161 /* Include the '\0' in the payload. */
162 ret = lttng_dynamic_buffer_append(
163 &payload->buffer, exclusion, len);
164 if (ret) {
165 goto end;
166 }
167
168 exclusions_appended_len += len;
169 }
170
171 assert(exclusions_len == exclusions_appended_len);
172
173 end:
174 return ret;
175 }
176
177 static bool lttng_event_rule_tracepoint_is_equal(
178 const struct lttng_event_rule *_a,
179 const struct lttng_event_rule *_b)
180 {
181 int i;
182 bool is_equal = false;
183 struct lttng_event_rule_tracepoint *a, *b;
184 unsigned int count_a, count_b;
185 enum lttng_event_rule_status status;
186
187 a = container_of(_a, struct lttng_event_rule_tracepoint, parent);
188 b = container_of(_b, struct lttng_event_rule_tracepoint, parent);
189
190 status = lttng_event_rule_tracepoint_get_exclusions_count(_a, &count_a);
191 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
192 status = lttng_event_rule_tracepoint_get_exclusions_count(_b, &count_b);
193 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
194
195 /* Quick checks. */
196 if (a->domain != b->domain) {
197 goto end;
198 }
199
200 if (count_a != count_b) {
201 goto end;
202 }
203
204 if (!!a->filter_expression != !!b->filter_expression) {
205 goto end;
206 }
207
208 /* Long check. */
209 assert(a->pattern);
210 assert(b->pattern);
211 if (strcmp(a->pattern, b->pattern)) {
212 goto end;
213 }
214
215 if (a->filter_expression && b->filter_expression) {
216 if (strcmp(a->filter_expression, b->filter_expression)) {
217 goto end;
218 }
219 } else if (!!a->filter_expression != !!b->filter_expression) {
220 /* One is set; not the other. */
221 goto end;
222 }
223
224 if (a->loglevel.type != b->loglevel.type) {
225 goto end;
226 }
227
228 if (a->loglevel.value != b->loglevel.value) {
229 goto end;
230 }
231
232 for (i = 0; i < count_a; i++) {
233 const char *exclusion_a, *exclusion_b;
234
235 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
236 _a, i, &exclusion_a);
237 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
238 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
239 _b, i, &exclusion_b);
240 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
241 if (strcmp(exclusion_a, exclusion_b)) {
242 goto end;
243 }
244 }
245
246 is_equal = true;
247 end:
248 return is_equal;
249 }
250
251 /*
252 * On success ret is 0;
253 *
254 * On error ret is negative.
255 *
256 * An event with NO loglevel and the name is * will return NULL.
257 */
258 static int generate_agent_filter(
259 const struct lttng_event_rule *rule, char **_agent_filter)
260 {
261 int err;
262 int ret = 0;
263 char *agent_filter = NULL;
264 const char *pattern;
265 const char *filter;
266 enum lttng_loglevel_type loglevel_type;
267 enum lttng_event_rule_status status;
268
269 assert(rule);
270 assert(_agent_filter);
271
272 status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
273 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
274 ret = -1;
275 goto end;
276 }
277
278 status = lttng_event_rule_tracepoint_get_filter(rule, &filter);
279 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
280 filter = NULL;
281 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
282 ret = -1;
283 goto end;
284 }
285
286 status = lttng_event_rule_tracepoint_get_log_level_type(
287 rule, &loglevel_type);
288 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
289 ret = -1;
290 goto end;
291 }
292
293 /* Don't add filter for the '*' event. */
294 if (strcmp(pattern, "*") != 0) {
295 if (filter) {
296 err = asprintf(&agent_filter,
297 "(%s) && (logger_name == \"%s\")",
298 filter, pattern);
299 } else {
300 err = asprintf(&agent_filter, "logger_name == \"%s\"",
301 pattern);
302 }
303
304 if (err < 0) {
305 PERROR("Failed to format agent filter string");
306 ret = -1;
307 goto end;
308 }
309 }
310
311 if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
312 const char *op;
313 int loglevel_value;
314
315 status = lttng_event_rule_tracepoint_get_log_level(
316 rule, &loglevel_value);
317 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
318 ret = -1;
319 goto end;
320 }
321
322 if (loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
323 op = ">=";
324 } else {
325 op = "==";
326 }
327
328 if (filter || agent_filter) {
329 char *new_filter;
330
331 err = asprintf(&new_filter,
332 "(%s) && (int_loglevel %s %d)",
333 agent_filter ? agent_filter : filter,
334 op, loglevel_value);
335 if (agent_filter) {
336 free(agent_filter);
337 }
338 agent_filter = new_filter;
339 } else {
340 err = asprintf(&agent_filter, "int_loglevel %s %d", op,
341 loglevel_value);
342 }
343
344 if (err < 0) {
345 PERROR("Failed to format agent filter string");
346 ret = -1;
347 goto end;
348 }
349 }
350
351 *_agent_filter = agent_filter;
352 agent_filter = NULL;
353
354 end:
355 free(agent_filter);
356 return ret;
357 }
358
359 static enum lttng_error_code
360 lttng_event_rule_tracepoint_generate_filter_bytecode(
361 struct lttng_event_rule *rule, uid_t uid, gid_t gid)
362 {
363 int ret;
364 enum lttng_error_code ret_code;
365 struct lttng_event_rule_tracepoint *tracepoint;
366 enum lttng_domain_type domain_type;
367 enum lttng_event_rule_status status;
368 const char *filter;
369 struct lttng_bytecode *bytecode = NULL;
370
371 assert(rule);
372
373 tracepoint = container_of(
374 rule, struct lttng_event_rule_tracepoint, parent);
375
376 status = lttng_event_rule_tracepoint_get_filter(rule, &filter);
377 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
378 filter = NULL;
379 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
380 ret_code = LTTNG_ERR_FILTER_INVAL;
381 goto end;
382 }
383
384 if (filter && filter[0] == '\0') {
385 ret_code = LTTNG_ERR_FILTER_INVAL;
386 goto error;
387 }
388
389 status = lttng_event_rule_tracepoint_get_domain_type(
390 rule, &domain_type);
391 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
392 ret_code = LTTNG_ERR_UNK;
393 goto error;
394 }
395
396 switch (domain_type) {
397 case LTTNG_DOMAIN_LOG4J:
398 case LTTNG_DOMAIN_JUL:
399 case LTTNG_DOMAIN_PYTHON:
400 {
401 char *agent_filter;
402
403 ret = generate_agent_filter(rule, &agent_filter);
404 if (ret) {
405 ret_code = LTTNG_ERR_FILTER_INVAL;
406 goto error;
407 }
408
409 tracepoint->internal_filter.filter = agent_filter;
410 break;
411 }
412 default:
413 {
414 if (filter) {
415 tracepoint->internal_filter.filter = strdup(filter);
416 if (tracepoint->internal_filter.filter == NULL) {
417 ret_code = LTTNG_ERR_NOMEM;
418 goto error;
419 }
420 } else {
421 tracepoint->internal_filter.filter = NULL;
422 }
423 break;
424 }
425 }
426
427 if (tracepoint->internal_filter.filter == NULL) {
428 ret_code = LTTNG_OK;
429 goto end;
430 }
431
432 ret = run_as_generate_filter_bytecode(
433 tracepoint->internal_filter.filter, uid, gid,
434 &bytecode);
435 if (ret) {
436 ret_code = LTTNG_ERR_FILTER_INVAL;
437 goto end;
438 }
439
440 tracepoint->internal_filter.bytecode = bytecode;
441 bytecode = NULL;
442 ret_code = LTTNG_OK;
443
444 error:
445 end:
446 free(bytecode);
447 return ret_code;
448 }
449
450 static const char *lttng_event_rule_tracepoint_get_internal_filter(
451 const struct lttng_event_rule *rule)
452 {
453 struct lttng_event_rule_tracepoint *tracepoint;
454
455 assert(rule);
456 tracepoint = container_of(
457 rule, struct lttng_event_rule_tracepoint, parent);
458 return tracepoint->internal_filter.filter;
459 }
460
461 static const struct lttng_bytecode *
462 lttng_event_rule_tracepoint_get_internal_filter_bytecode(
463 const struct lttng_event_rule *rule)
464 {
465 struct lttng_event_rule_tracepoint *tracepoint;
466
467 assert(rule);
468 tracepoint = container_of(
469 rule, struct lttng_event_rule_tracepoint, parent);
470 return tracepoint->internal_filter.bytecode;
471 }
472
473 static struct lttng_event_exclusion *
474 lttng_event_rule_tracepoint_generate_exclusions(
475 const struct lttng_event_rule *rule)
476 {
477 enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
478 enum lttng_event_rule_status status;
479 struct lttng_event_exclusion *local_exclusions = NULL;
480 struct lttng_event_exclusion *ret_exclusions = NULL;
481 unsigned int nb_exclusions = 0;
482 unsigned int i;
483
484 status = lttng_event_rule_tracepoint_get_domain_type(rule, &domain_type);
485 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
486
487 switch (domain_type) {
488 case LTTNG_DOMAIN_KERNEL:
489 case LTTNG_DOMAIN_JUL:
490 case LTTNG_DOMAIN_LOG4J:
491 case LTTNG_DOMAIN_PYTHON:
492 /* Not supported. */
493 ret_exclusions = NULL;
494 goto end;
495 case LTTNG_DOMAIN_UST:
496 /* Exclusions supported. */
497 break;
498 default:
499 abort();
500 }
501
502 status = lttng_event_rule_tracepoint_get_exclusions_count(
503 rule, &nb_exclusions);
504 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
505 if (nb_exclusions == 0) {
506 /* Nothing to do. */
507 ret_exclusions = NULL;
508 goto end;
509 }
510
511 local_exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
512 (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
513 if (!local_exclusions) {
514 PERROR("Failed to allocate exclusions buffer");
515 ret_exclusions = NULL;
516 goto end;
517 }
518
519 local_exclusions->count = nb_exclusions;
520 for (i = 0; i < nb_exclusions; i++) {
521 /* Truncation is already checked at the setter level. */
522 const char *tmp;
523
524 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
525 rule, i, &tmp);
526 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
527 strncpy(local_exclusions->names[i], tmp, LTTNG_SYMBOL_NAME_LEN);
528 local_exclusions->names[i][LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
529 }
530
531 /* Pass ownership. */
532 ret_exclusions = local_exclusions;
533 local_exclusions = NULL;
534 end:
535 free(local_exclusions);
536 return ret_exclusions;
537 }
538
539 static void destroy_lttng_exclusions_element(void *ptr)
540 {
541 free(ptr);
542 }
543
544 static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event(
545 const struct lttng_event_rule *rule)
546 {
547 const struct lttng_event_rule_tracepoint *tracepoint;
548 struct lttng_event *local_event = NULL;
549 struct lttng_event *event = NULL;
550
551 tracepoint = container_of(
552 rule, const struct lttng_event_rule_tracepoint, parent);
553
554 local_event = zmalloc(sizeof(*local_event));
555 if (!local_event) {
556 goto error;
557 }
558
559 local_event->type = LTTNG_EVENT_TRACEPOINT;
560 (void) strncpy(local_event->name, tracepoint->pattern,
561 sizeof(local_event->name) - 1);
562 local_event->name[sizeof(local_event->name) - 1] = '\0';
563 local_event->loglevel_type = tracepoint->loglevel.type;
564 local_event->loglevel = tracepoint->loglevel.value;
565
566 event = local_event;
567 local_event = NULL;
568 error:
569 free(local_event);
570 return event;
571 }
572
573 struct lttng_event_rule *lttng_event_rule_tracepoint_create(
574 enum lttng_domain_type domain_type)
575 {
576 struct lttng_event_rule *rule = NULL;
577 struct lttng_event_rule_tracepoint *tp_rule;
578
579 if (domain_type == LTTNG_DOMAIN_NONE) {
580 goto end;
581 }
582
583 tp_rule = zmalloc(sizeof(struct lttng_event_rule_tracepoint));
584 if (!tp_rule) {
585 goto end;
586 }
587
588 rule = &tp_rule->parent;
589 lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
590 tp_rule->parent.validate = lttng_event_rule_tracepoint_validate;
591 tp_rule->parent.serialize = lttng_event_rule_tracepoint_serialize;
592 tp_rule->parent.equal = lttng_event_rule_tracepoint_is_equal;
593 tp_rule->parent.destroy = lttng_event_rule_tracepoint_destroy;
594 tp_rule->parent.generate_filter_bytecode =
595 lttng_event_rule_tracepoint_generate_filter_bytecode;
596 tp_rule->parent.get_filter =
597 lttng_event_rule_tracepoint_get_internal_filter;
598 tp_rule->parent.get_filter_bytecode =
599 lttng_event_rule_tracepoint_get_internal_filter_bytecode;
600 tp_rule->parent.generate_exclusions =
601 lttng_event_rule_tracepoint_generate_exclusions;
602 tp_rule->parent.generate_lttng_event =
603 lttng_event_rule_tracepoint_generate_lttng_event;
604
605 tp_rule->domain = domain_type;
606 tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
607
608 lttng_dynamic_pointer_array_init(&tp_rule->exclusions,
609 destroy_lttng_exclusions_element);
610 end:
611 return rule;
612 }
613
614 LTTNG_HIDDEN
615 ssize_t lttng_event_rule_tracepoint_create_from_payload(
616 struct lttng_payload_view *view,
617 struct lttng_event_rule **_event_rule)
618 {
619 ssize_t ret, offset = 0;
620 int i;
621 enum lttng_event_rule_status status;
622 enum lttng_domain_type domain_type;
623 enum lttng_loglevel_type loglevel_type;
624 const struct lttng_event_rule_tracepoint_comm *tracepoint_comm;
625 const char *pattern;
626 const char *filter_expression = NULL;
627 const char **exclusions = NULL;
628 const uint32_t *exclusion_len;
629 const char *exclusion;
630 struct lttng_buffer_view current_buffer_view;
631 struct lttng_event_rule *rule = NULL;
632
633 if (!_event_rule) {
634 ret = -1;
635 goto end;
636 }
637
638 if (view->buffer.size < sizeof(*tracepoint_comm)) {
639 ERR("Failed to initialize from malformed event rule tracepoint: buffer too short to contain header.");
640 ret = -1;
641 goto end;
642 }
643
644 current_buffer_view = lttng_buffer_view_from_view(
645 &view->buffer, offset, sizeof(*tracepoint_comm));
646 tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data;
647
648 if (!tracepoint_comm) {
649 ret = -1;
650 goto end;
651 }
652
653 if (tracepoint_comm->domain_type <= LTTNG_DOMAIN_NONE ||
654 tracepoint_comm->domain_type > LTTNG_DOMAIN_PYTHON) {
655 /* Invalid domain value. */
656 ERR("Invalid domain type value (%i) found in tracepoint_comm buffer.",
657 (int) tracepoint_comm->domain_type);
658 ret = -1;
659 goto end;
660 }
661
662 domain_type = (enum lttng_domain_type) tracepoint_comm->domain_type;
663 rule = lttng_event_rule_tracepoint_create(domain_type);
664 if (!rule) {
665 ERR("Failed to create event rule tracepoint.");
666 ret = -1;
667 goto end;
668 }
669
670 loglevel_type = (enum lttng_loglevel_type)
671 tracepoint_comm->loglevel_type;
672 switch (loglevel_type) {
673 case LTTNG_EVENT_LOGLEVEL_ALL:
674 status = lttng_event_rule_tracepoint_set_log_level_all(rule);
675 break;
676 case LTTNG_EVENT_LOGLEVEL_RANGE:
677 status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(rule,
678 (enum lttng_loglevel_type) tracepoint_comm
679 ->loglevel_value);
680 break;
681 case LTTNG_EVENT_LOGLEVEL_SINGLE:
682 status = lttng_event_rule_tracepoint_set_log_level(rule,
683 (enum lttng_loglevel_type) tracepoint_comm
684 ->loglevel_value);
685 break;
686 default:
687 ERR("Failed to set event rule tracepoint loglevel: unknown loglevel type.");
688 ret = -1;
689 goto end;
690 }
691
692 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
693 ERR("Failed to set event rule tracepoint loglevel.");
694 }
695
696 /* Skip to payload. */
697 offset += current_buffer_view.size;
698
699 /* Map the pattern. */
700 current_buffer_view = lttng_buffer_view_from_view(
701 &view->buffer, offset, tracepoint_comm->pattern_len);
702 pattern = current_buffer_view.data;
703 if (!pattern) {
704 ret = -1;
705 goto end;
706 }
707
708 if (!lttng_buffer_view_contains_string(&current_buffer_view, pattern,
709 tracepoint_comm->pattern_len)) {
710 ret = -1;
711 goto end;
712 }
713
714 /* Skip after the pattern. */
715 offset += tracepoint_comm->pattern_len;
716
717 if (!tracepoint_comm->filter_expression_len) {
718 goto skip_filter_expression;
719 }
720
721 /* Map the filter_expression. */
722 current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset,
723 tracepoint_comm->filter_expression_len);
724 filter_expression = current_buffer_view.data;
725 if (!filter_expression) {
726 ret = -1;
727 goto end;
728 }
729
730 if (!lttng_buffer_view_contains_string(&current_buffer_view,
731 filter_expression,
732 tracepoint_comm->filter_expression_len)) {
733 ret = -1;
734 goto end;
735 }
736
737 /* Skip after the pattern. */
738 offset += tracepoint_comm->filter_expression_len;
739
740 skip_filter_expression:
741 for (i = 0; i < tracepoint_comm->exclusions_count; i++) {
742 current_buffer_view = lttng_buffer_view_from_view(
743 &view->buffer, offset, sizeof(*exclusion_len));
744 exclusion_len = (typeof(exclusion_len)) current_buffer_view.data;
745 if (!exclusion_len) {
746 ret = -1;
747 goto end;
748 }
749
750 offset += sizeof(*exclusion_len);
751 current_buffer_view = lttng_buffer_view_from_view(
752 &view->buffer, offset, *exclusion_len);
753 exclusion = current_buffer_view.data;
754 if (!lttng_buffer_view_contains_string(&current_buffer_view,
755 exclusion, *exclusion_len)) {
756 ret = -1;
757 goto end;
758 }
759
760 status = lttng_event_rule_tracepoint_add_exclusion(rule, exclusion);
761 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
762 ERR("Failed to add event rule tracepoint exclusion \"%s\".",
763 exclusion);
764 ret = -1;
765 goto end;
766 }
767
768 /* Skip to next exclusion. */
769 offset += *exclusion_len;
770 }
771
772 status = lttng_event_rule_tracepoint_set_pattern(rule, pattern);
773 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
774 ERR("Failed to set event rule tracepoint pattern.");
775 ret = -1;
776 goto end;
777 }
778
779 if (filter_expression) {
780 status = lttng_event_rule_tracepoint_set_filter(
781 rule, filter_expression);
782 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
783 ERR("Failed to set event rule tracepoint pattern.");
784 ret = -1;
785 goto end;
786 }
787 }
788
789 *_event_rule = rule;
790 rule = NULL;
791 ret = offset;
792 end:
793 free(exclusions);
794 lttng_event_rule_destroy(rule);
795 return ret;
796 }
797
798 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_pattern(
799 struct lttng_event_rule *rule, const char *pattern)
800 {
801 char *pattern_copy = NULL;
802 struct lttng_event_rule_tracepoint *tracepoint;
803 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
804
805 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern ||
806 strlen(pattern) == 0) {
807 status = LTTNG_EVENT_RULE_STATUS_INVALID;
808 goto end;
809 }
810
811 tracepoint = container_of(
812 rule, struct lttng_event_rule_tracepoint, parent);
813 pattern_copy = strdup(pattern);
814 if (!pattern_copy) {
815 status = LTTNG_EVENT_RULE_STATUS_ERROR;
816 goto end;
817 }
818
819 free(tracepoint->pattern);
820
821 tracepoint->pattern = pattern_copy;
822 pattern_copy = NULL;
823 end:
824 return status;
825 }
826
827 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_pattern(
828 const struct lttng_event_rule *rule, const char **pattern)
829 {
830 struct lttng_event_rule_tracepoint *tracepoint;
831 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
832
833 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern) {
834 status = LTTNG_EVENT_RULE_STATUS_INVALID;
835 goto end;
836 }
837
838 tracepoint = container_of(
839 rule, struct lttng_event_rule_tracepoint, parent);
840 if (!tracepoint->pattern) {
841 status = LTTNG_EVENT_RULE_STATUS_UNSET;
842 goto end;
843 }
844
845 *pattern = tracepoint->pattern;
846 end:
847 return status;
848 }
849
850 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_domain_type(
851 const struct lttng_event_rule *rule,
852 enum lttng_domain_type *type)
853 {
854 struct lttng_event_rule_tracepoint *tracepoint;
855 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
856
857 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
858 status = LTTNG_EVENT_RULE_STATUS_INVALID;
859 goto end;
860 }
861
862 tracepoint = container_of(
863 rule, struct lttng_event_rule_tracepoint, parent);
864 *type = tracepoint->domain;
865 end:
866 return status;
867 }
868
869 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_filter(
870 struct lttng_event_rule *rule, const char *expression)
871 {
872 char *expression_copy = NULL;
873 struct lttng_event_rule_tracepoint *tracepoint;
874 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
875
876 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression ||
877 strlen(expression) == 0) {
878 status = LTTNG_EVENT_RULE_STATUS_INVALID;
879 goto end;
880 }
881
882 tracepoint = container_of(
883 rule, struct lttng_event_rule_tracepoint, parent);
884 expression_copy = strdup(expression);
885 if (!expression_copy) {
886 PERROR("Failed to copy filter expression");
887 status = LTTNG_EVENT_RULE_STATUS_ERROR;
888 goto end;
889 }
890
891 if (tracepoint->filter_expression) {
892 free(tracepoint->filter_expression);
893 }
894
895 tracepoint->filter_expression = expression_copy;
896 expression_copy = NULL;
897 end:
898 return status;
899 }
900
901 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter(
902 const struct lttng_event_rule *rule, const char **expression)
903 {
904 struct lttng_event_rule_tracepoint *tracepoint;
905 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
906
907 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression) {
908 status = LTTNG_EVENT_RULE_STATUS_INVALID;
909 goto end;
910 }
911
912 tracepoint = container_of(
913 rule, struct lttng_event_rule_tracepoint, parent);
914 if (!tracepoint->filter_expression) {
915 status = LTTNG_EVENT_RULE_STATUS_UNSET;
916 goto end;
917 }
918
919 *expression = tracepoint->filter_expression;
920 end:
921 return status;
922 }
923
924 static bool log_level_value_valid(
925 int level, enum lttng_domain_type domain)
926 {
927 bool valid = false;
928
929 switch (domain) {
930 case LTTNG_DOMAIN_KERNEL:
931 case LTTNG_DOMAIN_UST:
932 if (level < LTTNG_LOGLEVEL_EMERG) {
933 /* Invalid. */
934 goto end;
935 }
936 if (level > LTTNG_LOGLEVEL_DEBUG) {
937 /* Invalid. */
938 goto end;
939 }
940
941 valid = true;
942 break;
943 case LTTNG_DOMAIN_JUL:
944 case LTTNG_DOMAIN_LOG4J:
945 case LTTNG_DOMAIN_PYTHON:
946 /*
947 * For both JUL and LOG4J custom log level are possible and can
948 * spawn the entire int32 range.
949 * For python, custom log level are possible, it is not clear if
950 * negative value are accepted (NOTSET == 0) but the source code
951 * validate against the int type implying that negative values
952 * are accepted.
953 */
954 valid = true;
955 goto end;
956
957 case LTTNG_DOMAIN_NONE:
958 default:
959 abort();
960 }
961
962 end:
963 return valid;
964 }
965
966 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
967 struct lttng_event_rule *rule, int level)
968 {
969 struct lttng_event_rule_tracepoint *tracepoint;
970 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
971
972 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
973 status = LTTNG_EVENT_RULE_STATUS_INVALID;
974 goto end;
975 }
976
977 tracepoint = container_of(
978 rule, struct lttng_event_rule_tracepoint, parent);
979
980 if (!log_level_value_valid(level, tracepoint->domain)) {
981 status = LTTNG_EVENT_RULE_STATUS_INVALID;
982 goto end;
983 }
984
985 tracepoint->loglevel.value = level;
986 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_SINGLE;
987 end:
988 return status;
989 }
990
991 enum lttng_event_rule_status
992 lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
993 struct lttng_event_rule *rule, int level)
994 {
995 struct lttng_event_rule_tracepoint *tracepoint;
996 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
997
998 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
999 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1000 goto end;
1001 }
1002
1003 tracepoint = container_of(
1004 rule, struct lttng_event_rule_tracepoint, parent);
1005
1006 if (!log_level_value_valid(level, tracepoint->domain)) {
1007 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1008 goto end;
1009 }
1010
1011 tracepoint->loglevel.value = level;
1012 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_RANGE;
1013 end:
1014 return status;
1015 }
1016
1017 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_all(
1018 struct lttng_event_rule *rule)
1019 {
1020 struct lttng_event_rule_tracepoint *tracepoint;
1021 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1022
1023 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1024 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1025 goto end;
1026 }
1027
1028 tracepoint = container_of(
1029 rule, struct lttng_event_rule_tracepoint, parent);
1030 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
1031 end:
1032 return status;
1033 }
1034
1035 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_type(
1036 const struct lttng_event_rule *rule,
1037 enum lttng_loglevel_type *type)
1038 {
1039 struct lttng_event_rule_tracepoint *tracepoint;
1040 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1041
1042 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
1043 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1044 goto end;
1045 }
1046
1047 tracepoint = container_of(
1048 rule, struct lttng_event_rule_tracepoint, parent);
1049 *type = tracepoint->loglevel.type;
1050 end:
1051 return status;
1052 }
1053
1054 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level(
1055 const struct lttng_event_rule *rule, int *level)
1056 {
1057 struct lttng_event_rule_tracepoint *tracepoint;
1058 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1059
1060 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !level) {
1061 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1062 goto end;
1063 }
1064
1065 tracepoint = container_of(
1066 rule, struct lttng_event_rule_tracepoint, parent);
1067 if (tracepoint->loglevel.type == LTTNG_EVENT_LOGLEVEL_ALL) {
1068 status = LTTNG_EVENT_RULE_STATUS_UNSET;
1069 goto end;
1070 }
1071
1072 *level = tracepoint->loglevel.value;
1073 end:
1074 return status;
1075 }
1076
1077 enum lttng_event_rule_status lttng_event_rule_tracepoint_add_exclusion(
1078 struct lttng_event_rule *rule,
1079 const char *exclusion)
1080 {
1081 int ret;
1082 char *exclusion_copy = NULL;
1083 struct lttng_event_rule_tracepoint *tracepoint;
1084 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1085 enum lttng_domain_type domain_type;
1086
1087 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) ||
1088 !exclusion) {
1089 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1090 goto end;
1091 }
1092
1093 tracepoint = container_of(
1094 rule, struct lttng_event_rule_tracepoint, parent);
1095
1096 status = lttng_event_rule_tracepoint_get_domain_type(
1097 rule, &domain_type);
1098 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
1099 goto end;
1100 }
1101
1102 switch (domain_type) {
1103 case LTTNG_DOMAIN_KERNEL:
1104 case LTTNG_DOMAIN_JUL:
1105 case LTTNG_DOMAIN_LOG4J:
1106 case LTTNG_DOMAIN_PYTHON:
1107 status = LTTNG_EVENT_RULE_STATUS_UNSUPPORTED;
1108 goto end;
1109 case LTTNG_DOMAIN_UST:
1110 /* Exclusions supported. */
1111 break;
1112 default:
1113 abort();
1114 }
1115
1116 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
1117 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1118 goto end;
1119 }
1120
1121 exclusion_copy = strdup(exclusion);
1122 if (!exclusion_copy) {
1123 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1124 goto end;
1125 }
1126
1127 ret = lttng_dynamic_pointer_array_add_pointer(&tracepoint->exclusions,
1128 exclusion_copy);
1129 if (ret < 0) {
1130 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1131 goto end;
1132 }
1133
1134 exclusion_copy = NULL;
1135 end:
1136 free(exclusion_copy);
1137 return status;
1138 }
1139
1140 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusions_count(
1141 const struct lttng_event_rule *rule, unsigned int *count)
1142 {
1143 struct lttng_event_rule_tracepoint *tracepoint;
1144 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1145
1146 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !count) {
1147 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1148 goto end;
1149 }
1150
1151 tracepoint = container_of(
1152 rule, struct lttng_event_rule_tracepoint, parent);
1153 *count = lttng_dynamic_pointer_array_get_count(&tracepoint->exclusions);
1154 end:
1155 return status;
1156 }
1157
1158 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusion_at_index(
1159 const struct lttng_event_rule *rule,
1160 unsigned int index,
1161 const char **exclusion)
1162 {
1163 unsigned int count;
1164 struct lttng_event_rule_tracepoint *tracepoint;
1165 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1166
1167 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !exclusion) {
1168 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1169 goto end;
1170 }
1171
1172 tracepoint = container_of(
1173 rule, struct lttng_event_rule_tracepoint, parent);
1174 if (lttng_event_rule_tracepoint_get_exclusions_count(rule, &count) !=
1175 LTTNG_EVENT_RULE_STATUS_OK) {
1176 goto end;
1177 }
1178
1179 if (index >= count) {
1180 goto end;
1181 }
1182
1183 *exclusion = lttng_dynamic_pointer_array_get_pointer(
1184 &tracepoint->exclusions, index);
1185 end:
1186 return status;
1187 }
This page took 0.055817 seconds and 5 git commands to generate.