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