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