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