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