ust-app: implement event notifier support
[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 enum lttng_event_rule_generate_exclusions_status
477 lttng_event_rule_tracepoint_generate_exclusions(
478 const struct lttng_event_rule *rule,
479 struct lttng_event_exclusion **_exclusions)
480 {
481 unsigned int nb_exclusions = 0, i;
482 enum lttng_domain_type domain_type;
483 struct lttng_event_exclusion *exclusions;
484 enum lttng_event_rule_status event_rule_status;
485 enum lttng_event_rule_generate_exclusions_status ret_status;
486
487 assert(_exclusions);
488
489 event_rule_status = lttng_event_rule_tracepoint_get_domain_type(
490 rule, &domain_type);
491 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
492
493 switch (domain_type) {
494 case LTTNG_DOMAIN_KERNEL:
495 case LTTNG_DOMAIN_JUL:
496 case LTTNG_DOMAIN_LOG4J:
497 case LTTNG_DOMAIN_PYTHON:
498 /* Not supported. */
499 exclusions = NULL;
500 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
501 goto end;
502 case LTTNG_DOMAIN_UST:
503 /* Exclusions supported. */
504 break;
505 default:
506 /* Unknown domain. */
507 abort();
508 }
509
510 event_rule_status = lttng_event_rule_tracepoint_get_exclusions_count(
511 rule, &nb_exclusions);
512 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
513 if (nb_exclusions == 0) {
514 /* Nothing to do. */
515 exclusions = NULL;
516 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
517 goto end;
518 }
519
520 exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
521 (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
522 if (!exclusions) {
523 PERROR("Failed to allocate exclusions buffer");
524 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY;
525 goto end;
526 }
527
528 exclusions->count = nb_exclusions;
529 for (i = 0; i < nb_exclusions; i++) {
530 int copy_ret;
531 const char *exclusion_str;
532
533 event_rule_status =
534 lttng_event_rule_tracepoint_get_exclusion_at_index(
535 rule, i, &exclusion_str);
536 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
537
538 copy_ret = lttng_strncpy(exclusions->names[i], exclusion_str,
539 LTTNG_SYMBOL_NAME_LEN);
540 if (copy_ret) {
541 free(exclusions);
542 exclusions = NULL;
543 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR;
544 goto end;
545 }
546 }
547
548 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK;
549
550 end:
551 *_exclusions = exclusions;
552 return ret_status;
553 }
554
555 static void destroy_lttng_exclusions_element(void *ptr)
556 {
557 free(ptr);
558 }
559
560 static unsigned long lttng_event_rule_tracepoint_hash(
561 const struct lttng_event_rule *rule)
562 {
563 unsigned long hash;
564 unsigned int i, exclusion_count;
565 enum lttng_event_rule_status status;
566 struct lttng_event_rule_tracepoint *tp_rule =
567 container_of(rule, typeof(*tp_rule), parent);
568
569 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_TRACEPOINT,
570 lttng_ht_seed);
571 hash ^= hash_key_ulong((void *) tp_rule->domain, lttng_ht_seed);
572 hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed);
573
574 if (tp_rule->filter_expression) {
575 hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed);
576 }
577
578 hash ^= hash_key_ulong((void *) tp_rule->loglevel.type,
579 lttng_ht_seed);
580 if (tp_rule->loglevel.type != LTTNG_EVENT_LOGLEVEL_ALL) {
581 hash ^= hash_key_ulong(
582 (void *) (unsigned long) tp_rule->loglevel.value,
583 lttng_ht_seed);
584 }
585
586 status = lttng_event_rule_tracepoint_get_exclusions_count(rule,
587 &exclusion_count);
588 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
589
590 for (i = 0; i < exclusion_count; i++) {
591 const char *exclusion;
592
593 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
594 rule, i, &exclusion);
595 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
596 hash ^= hash_key_str(exclusion, lttng_ht_seed);
597 }
598
599 return hash;
600 }
601
602 struct lttng_event_rule *lttng_event_rule_tracepoint_create(
603 enum lttng_domain_type domain_type)
604 {
605 struct lttng_event_rule *rule = NULL;
606 struct lttng_event_rule_tracepoint *tp_rule;
607
608 if (domain_type == LTTNG_DOMAIN_NONE) {
609 goto end;
610 }
611
612 tp_rule = zmalloc(sizeof(struct lttng_event_rule_tracepoint));
613 if (!tp_rule) {
614 goto end;
615 }
616
617 rule = &tp_rule->parent;
618 lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
619 tp_rule->parent.validate = lttng_event_rule_tracepoint_validate;
620 tp_rule->parent.serialize = lttng_event_rule_tracepoint_serialize;
621 tp_rule->parent.equal = lttng_event_rule_tracepoint_is_equal;
622 tp_rule->parent.destroy = lttng_event_rule_tracepoint_destroy;
623 tp_rule->parent.generate_filter_bytecode =
624 lttng_event_rule_tracepoint_generate_filter_bytecode;
625 tp_rule->parent.get_filter =
626 lttng_event_rule_tracepoint_get_internal_filter;
627 tp_rule->parent.get_filter_bytecode =
628 lttng_event_rule_tracepoint_get_internal_filter_bytecode;
629 tp_rule->parent.generate_exclusions =
630 lttng_event_rule_tracepoint_generate_exclusions;
631 tp_rule->parent.hash = lttng_event_rule_tracepoint_hash;
632
633 tp_rule->domain = domain_type;
634 tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
635
636 lttng_dynamic_pointer_array_init(&tp_rule->exclusions,
637 destroy_lttng_exclusions_element);
638 end:
639 return rule;
640 }
641
642 LTTNG_HIDDEN
643 ssize_t lttng_event_rule_tracepoint_create_from_payload(
644 struct lttng_payload_view *view,
645 struct lttng_event_rule **_event_rule)
646 {
647 ssize_t ret, offset = 0;
648 int i;
649 enum lttng_event_rule_status status;
650 enum lttng_domain_type domain_type;
651 enum lttng_loglevel_type loglevel_type;
652 const struct lttng_event_rule_tracepoint_comm *tracepoint_comm;
653 const char *pattern;
654 const char *filter_expression = NULL;
655 const char **exclusions = NULL;
656 const uint32_t *exclusion_len;
657 const char *exclusion;
658 struct lttng_buffer_view current_buffer_view;
659 struct lttng_event_rule *rule = NULL;
660
661 if (!_event_rule) {
662 ret = -1;
663 goto end;
664 }
665
666 current_buffer_view = lttng_buffer_view_from_view(
667 &view->buffer, offset, sizeof(*tracepoint_comm));
668 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
669 ERR("Failed to initialize from malformed event rule tracepoint: buffer too short to contain header.");
670 ret = -1;
671 goto end;
672 }
673
674 tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data;
675
676 if (tracepoint_comm->domain_type <= LTTNG_DOMAIN_NONE ||
677 tracepoint_comm->domain_type > LTTNG_DOMAIN_PYTHON) {
678 /* Invalid domain value. */
679 ERR("Invalid domain type value (%i) found in tracepoint_comm buffer.",
680 (int) tracepoint_comm->domain_type);
681 ret = -1;
682 goto end;
683 }
684
685 domain_type = (enum lttng_domain_type) tracepoint_comm->domain_type;
686 rule = lttng_event_rule_tracepoint_create(domain_type);
687 if (!rule) {
688 ERR("Failed to create event rule tracepoint.");
689 ret = -1;
690 goto end;
691 }
692
693 loglevel_type = (enum lttng_loglevel_type)
694 tracepoint_comm->loglevel_type;
695 switch (loglevel_type) {
696 case LTTNG_EVENT_LOGLEVEL_ALL:
697 status = lttng_event_rule_tracepoint_set_log_level_all(rule);
698 break;
699 case LTTNG_EVENT_LOGLEVEL_RANGE:
700 status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(rule,
701 (enum lttng_loglevel_type) tracepoint_comm
702 ->loglevel_value);
703 break;
704 case LTTNG_EVENT_LOGLEVEL_SINGLE:
705 status = lttng_event_rule_tracepoint_set_log_level(rule,
706 (enum lttng_loglevel_type) tracepoint_comm
707 ->loglevel_value);
708 break;
709 default:
710 ERR("Failed to set event rule tracepoint loglevel: unknown loglevel type.");
711 ret = -1;
712 goto end;
713 }
714
715 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
716 ERR("Failed to set event rule tracepoint loglevel.");
717 }
718
719 /* Skip to payload. */
720 offset += current_buffer_view.size;
721
722 /* Map the pattern. */
723 current_buffer_view = lttng_buffer_view_from_view(
724 &view->buffer, offset, tracepoint_comm->pattern_len);
725
726 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
727 ret = -1;
728 goto end;
729 }
730
731 pattern = current_buffer_view.data;
732 if (!lttng_buffer_view_contains_string(&current_buffer_view, pattern,
733 tracepoint_comm->pattern_len)) {
734 ret = -1;
735 goto end;
736 }
737
738 /* Skip after the pattern. */
739 offset += tracepoint_comm->pattern_len;
740
741 if (!tracepoint_comm->filter_expression_len) {
742 goto skip_filter_expression;
743 }
744
745 /* Map the filter_expression. */
746 current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset,
747 tracepoint_comm->filter_expression_len);
748 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
749 ret = -1;
750 goto end;
751 }
752
753 filter_expression = current_buffer_view.data;
754 if (!lttng_buffer_view_contains_string(&current_buffer_view,
755 filter_expression,
756 tracepoint_comm->filter_expression_len)) {
757 ret = -1;
758 goto end;
759 }
760
761 /* Skip after the pattern. */
762 offset += tracepoint_comm->filter_expression_len;
763
764 skip_filter_expression:
765 for (i = 0; i < tracepoint_comm->exclusions_count; i++) {
766 current_buffer_view = lttng_buffer_view_from_view(
767 &view->buffer, offset, sizeof(*exclusion_len));
768 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
769 ret = -1;
770 goto end;
771 }
772
773 exclusion_len = (typeof(exclusion_len)) current_buffer_view.data;
774 offset += sizeof(*exclusion_len);
775
776 current_buffer_view = lttng_buffer_view_from_view(
777 &view->buffer, offset, *exclusion_len);
778 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
779 ret = -1;
780 goto end;
781 }
782
783 exclusion = current_buffer_view.data;
784 if (!lttng_buffer_view_contains_string(&current_buffer_view,
785 exclusion, *exclusion_len)) {
786 ret = -1;
787 goto end;
788 }
789
790 status = lttng_event_rule_tracepoint_add_exclusion(rule, exclusion);
791 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
792 ERR("Failed to add event rule tracepoint exclusion \"%s\".",
793 exclusion);
794 ret = -1;
795 goto end;
796 }
797
798 /* Skip to next exclusion. */
799 offset += *exclusion_len;
800 }
801
802 status = lttng_event_rule_tracepoint_set_pattern(rule, pattern);
803 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
804 ERR("Failed to set event rule tracepoint pattern.");
805 ret = -1;
806 goto end;
807 }
808
809 if (filter_expression) {
810 status = lttng_event_rule_tracepoint_set_filter(
811 rule, filter_expression);
812 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
813 ERR("Failed to set event rule tracepoint pattern.");
814 ret = -1;
815 goto end;
816 }
817 }
818
819 *_event_rule = rule;
820 rule = NULL;
821 ret = offset;
822 end:
823 free(exclusions);
824 lttng_event_rule_destroy(rule);
825 return ret;
826 }
827
828 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_pattern(
829 struct lttng_event_rule *rule, const char *pattern)
830 {
831 char *pattern_copy = NULL;
832 struct lttng_event_rule_tracepoint *tracepoint;
833 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
834
835 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern ||
836 strlen(pattern) == 0) {
837 status = LTTNG_EVENT_RULE_STATUS_INVALID;
838 goto end;
839 }
840
841 tracepoint = container_of(
842 rule, struct lttng_event_rule_tracepoint, parent);
843 pattern_copy = strdup(pattern);
844 if (!pattern_copy) {
845 status = LTTNG_EVENT_RULE_STATUS_ERROR;
846 goto end;
847 }
848
849 free(tracepoint->pattern);
850
851 tracepoint->pattern = pattern_copy;
852 pattern_copy = NULL;
853 end:
854 return status;
855 }
856
857 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_pattern(
858 const struct lttng_event_rule *rule, const char **pattern)
859 {
860 struct lttng_event_rule_tracepoint *tracepoint;
861 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
862
863 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern) {
864 status = LTTNG_EVENT_RULE_STATUS_INVALID;
865 goto end;
866 }
867
868 tracepoint = container_of(
869 rule, struct lttng_event_rule_tracepoint, parent);
870 if (!tracepoint->pattern) {
871 status = LTTNG_EVENT_RULE_STATUS_UNSET;
872 goto end;
873 }
874
875 *pattern = tracepoint->pattern;
876 end:
877 return status;
878 }
879
880 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_domain_type(
881 const struct lttng_event_rule *rule,
882 enum lttng_domain_type *type)
883 {
884 struct lttng_event_rule_tracepoint *tracepoint;
885 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
886
887 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
888 status = LTTNG_EVENT_RULE_STATUS_INVALID;
889 goto end;
890 }
891
892 tracepoint = container_of(
893 rule, struct lttng_event_rule_tracepoint, parent);
894 *type = tracepoint->domain;
895 end:
896 return status;
897 }
898
899 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_filter(
900 struct lttng_event_rule *rule, const char *expression)
901 {
902 char *expression_copy = NULL;
903 struct lttng_event_rule_tracepoint *tracepoint;
904 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
905
906 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression ||
907 strlen(expression) == 0) {
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 expression_copy = strdup(expression);
915 if (!expression_copy) {
916 PERROR("Failed to copy filter expression");
917 status = LTTNG_EVENT_RULE_STATUS_ERROR;
918 goto end;
919 }
920
921 if (tracepoint->filter_expression) {
922 free(tracepoint->filter_expression);
923 }
924
925 tracepoint->filter_expression = expression_copy;
926 expression_copy = NULL;
927 end:
928 return status;
929 }
930
931 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter(
932 const struct lttng_event_rule *rule, const char **expression)
933 {
934 struct lttng_event_rule_tracepoint *tracepoint;
935 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
936
937 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression) {
938 status = LTTNG_EVENT_RULE_STATUS_INVALID;
939 goto end;
940 }
941
942 tracepoint = container_of(
943 rule, struct lttng_event_rule_tracepoint, parent);
944 if (!tracepoint->filter_expression) {
945 status = LTTNG_EVENT_RULE_STATUS_UNSET;
946 goto end;
947 }
948
949 *expression = tracepoint->filter_expression;
950 end:
951 return status;
952 }
953
954 static bool log_level_value_valid(
955 int level, enum lttng_domain_type domain)
956 {
957 bool valid = false;
958
959 switch (domain) {
960 case LTTNG_DOMAIN_KERNEL:
961 case LTTNG_DOMAIN_UST:
962 if (level < LTTNG_LOGLEVEL_EMERG) {
963 /* Invalid. */
964 goto end;
965 }
966 if (level > LTTNG_LOGLEVEL_DEBUG) {
967 /* Invalid. */
968 goto end;
969 }
970
971 valid = true;
972 break;
973 case LTTNG_DOMAIN_JUL:
974 case LTTNG_DOMAIN_LOG4J:
975 case LTTNG_DOMAIN_PYTHON:
976 /*
977 * For both JUL and LOG4J custom log level are possible and can
978 * spawn the entire int32 range.
979 * For python, custom log level are possible, it is not clear if
980 * negative value are accepted (NOTSET == 0) but the source code
981 * validate against the int type implying that negative values
982 * are accepted.
983 */
984 valid = true;
985 goto end;
986
987 case LTTNG_DOMAIN_NONE:
988 default:
989 abort();
990 }
991
992 end:
993 return valid;
994 }
995
996 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
997 struct lttng_event_rule *rule, int level)
998 {
999 struct lttng_event_rule_tracepoint *tracepoint;
1000 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1001
1002 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1003 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1004 goto end;
1005 }
1006
1007 tracepoint = container_of(
1008 rule, struct lttng_event_rule_tracepoint, parent);
1009
1010 if (!log_level_value_valid(level, tracepoint->domain)) {
1011 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1012 goto end;
1013 }
1014
1015 tracepoint->loglevel.value = level;
1016 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_SINGLE;
1017 end:
1018 return status;
1019 }
1020
1021 enum lttng_event_rule_status
1022 lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
1023 struct lttng_event_rule *rule, int level)
1024 {
1025 struct lttng_event_rule_tracepoint *tracepoint;
1026 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1027
1028 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1029 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1030 goto end;
1031 }
1032
1033 tracepoint = container_of(
1034 rule, struct lttng_event_rule_tracepoint, parent);
1035
1036 if (!log_level_value_valid(level, tracepoint->domain)) {
1037 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1038 goto end;
1039 }
1040
1041 tracepoint->loglevel.value = level;
1042 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_RANGE;
1043 end:
1044 return status;
1045 }
1046
1047 enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_all(
1048 struct lttng_event_rule *rule)
1049 {
1050 struct lttng_event_rule_tracepoint *tracepoint;
1051 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1052
1053 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1054 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1055 goto end;
1056 }
1057
1058 tracepoint = container_of(
1059 rule, struct lttng_event_rule_tracepoint, parent);
1060 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
1061 end:
1062 return status;
1063 }
1064
1065 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_type(
1066 const struct lttng_event_rule *rule,
1067 enum lttng_loglevel_type *type)
1068 {
1069 struct lttng_event_rule_tracepoint *tracepoint;
1070 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1071
1072 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
1073 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1074 goto end;
1075 }
1076
1077 tracepoint = container_of(
1078 rule, struct lttng_event_rule_tracepoint, parent);
1079 *type = tracepoint->loglevel.type;
1080 end:
1081 return status;
1082 }
1083
1084 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level(
1085 const struct lttng_event_rule *rule, int *level)
1086 {
1087 struct lttng_event_rule_tracepoint *tracepoint;
1088 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1089
1090 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !level) {
1091 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1092 goto end;
1093 }
1094
1095 tracepoint = container_of(
1096 rule, struct lttng_event_rule_tracepoint, parent);
1097 if (tracepoint->loglevel.type == LTTNG_EVENT_LOGLEVEL_ALL) {
1098 status = LTTNG_EVENT_RULE_STATUS_UNSET;
1099 goto end;
1100 }
1101
1102 *level = tracepoint->loglevel.value;
1103 end:
1104 return status;
1105 }
1106
1107 enum lttng_event_rule_status lttng_event_rule_tracepoint_add_exclusion(
1108 struct lttng_event_rule *rule,
1109 const char *exclusion)
1110 {
1111 int ret;
1112 char *exclusion_copy = NULL;
1113 struct lttng_event_rule_tracepoint *tracepoint;
1114 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1115 enum lttng_domain_type domain_type;
1116
1117 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) ||
1118 !exclusion) {
1119 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1120 goto end;
1121 }
1122
1123 tracepoint = container_of(
1124 rule, struct lttng_event_rule_tracepoint, parent);
1125
1126 status = lttng_event_rule_tracepoint_get_domain_type(
1127 rule, &domain_type);
1128 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
1129 goto end;
1130 }
1131
1132 switch (domain_type) {
1133 case LTTNG_DOMAIN_KERNEL:
1134 case LTTNG_DOMAIN_JUL:
1135 case LTTNG_DOMAIN_LOG4J:
1136 case LTTNG_DOMAIN_PYTHON:
1137 status = LTTNG_EVENT_RULE_STATUS_UNSUPPORTED;
1138 goto end;
1139 case LTTNG_DOMAIN_UST:
1140 /* Exclusions supported. */
1141 break;
1142 default:
1143 abort();
1144 }
1145
1146 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
1147 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1148 goto end;
1149 }
1150
1151 exclusion_copy = strdup(exclusion);
1152 if (!exclusion_copy) {
1153 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1154 goto end;
1155 }
1156
1157 ret = lttng_dynamic_pointer_array_add_pointer(&tracepoint->exclusions,
1158 exclusion_copy);
1159 if (ret < 0) {
1160 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1161 goto end;
1162 }
1163
1164 exclusion_copy = NULL;
1165 end:
1166 free(exclusion_copy);
1167 return status;
1168 }
1169
1170 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusions_count(
1171 const struct lttng_event_rule *rule, unsigned int *count)
1172 {
1173 struct lttng_event_rule_tracepoint *tracepoint;
1174 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1175
1176 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !count) {
1177 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1178 goto end;
1179 }
1180
1181 tracepoint = container_of(
1182 rule, struct lttng_event_rule_tracepoint, parent);
1183 *count = lttng_dynamic_pointer_array_get_count(&tracepoint->exclusions);
1184 end:
1185 return status;
1186 }
1187
1188 enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusion_at_index(
1189 const struct lttng_event_rule *rule,
1190 unsigned int index,
1191 const char **exclusion)
1192 {
1193 unsigned int count;
1194 struct lttng_event_rule_tracepoint *tracepoint;
1195 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1196
1197 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !exclusion) {
1198 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1199 goto end;
1200 }
1201
1202 tracepoint = container_of(
1203 rule, struct lttng_event_rule_tracepoint, parent);
1204 if (lttng_event_rule_tracepoint_get_exclusions_count(rule, &count) !=
1205 LTTNG_EVENT_RULE_STATUS_OK) {
1206 goto end;
1207 }
1208
1209 if (index >= count) {
1210 goto end;
1211 }
1212
1213 *exclusion = lttng_dynamic_pointer_array_get_pointer(
1214 &tracepoint->exclusions, index);
1215 end:
1216 return status;
1217 }
This page took 0.093821 seconds and 4 git commands to generate.