lttng-ctl: Introduce lttng_log_level_rule
[lttng-tools.git] / src / common / event-rule / tracepoint.c
CommitLineData
6d420eff
JR
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>
58daac01 9#include <common/credentials.h>
6d420eff
JR
10#include <common/error.h>
11#include <common/macros.h>
85b05318 12#include <common/optional.h>
6d420eff
JR
13#include <common/payload.h>
14#include <common/payload-view.h>
15#include <common/runas.h>
959e3c66
JR
16#include <common/hashtable/hashtable.h>
17#include <common/hashtable/utils.h>
6d420eff
JR
18#include <lttng/event-rule/event-rule-internal.h>
19#include <lttng/event-rule/tracepoint-internal.h>
85b05318 20#include <lttng/log-level-rule.h>
44760c20 21#include <lttng/event.h>
6d420eff
JR
22
23#define IS_TRACEPOINT_EVENT_RULE(rule) \
24 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_TRACEPOINT)
25
26static 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
45static 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;
71end:
72 return valid;
73}
74
75static int lttng_event_rule_tracepoint_serialize(
76 const struct lttng_event_rule *rule,
77 struct lttng_payload *payload)
78{
79 int ret, i;
85b05318
JR
80 size_t pattern_len, filter_expression_len, exclusions_len, header_offset;
81 size_t size_before_log_level_rule;
6d420eff
JR
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;
85b05318 87 struct lttng_event_rule_tracepoint_comm *header;
6d420eff
JR
88
89 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
90 ret = -1;
91 goto end;
92 }
93
85b05318
JR
94 header_offset = payload->buffer.size;
95
6d420eff
JR
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;
6d420eff
JR
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
85b05318
JR
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
6d420eff
JR
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
191end:
192 return ret;
193}
194
195static 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
85b05318
JR
242 if (!lttng_log_level_rule_is_equal(
243 a->log_level_rule, b->log_level_rule)) {
6d420eff
JR
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;
262end:
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 */
273static 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;
85b05318 281 const struct lttng_log_level_rule *log_level_rule = NULL;
6d420eff
JR
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
6d420eff
JR
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
85b05318
JR
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;
6d420eff 324 const char *op;
85b05318 325 int level;
6d420eff 326
85b05318
JR
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();
6d420eff
JR
341 }
342
85b05318
JR
343 if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) {
344 ret = -1;
345 goto end;
6d420eff
JR
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,
85b05318 354 op, level);
6d420eff
JR
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,
85b05318 361 level);
6d420eff
JR
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
374end:
375 free(agent_filter);
376 return ret;
377}
378
379static enum lttng_error_code
380lttng_event_rule_tracepoint_generate_filter_bytecode(
58daac01
JR
381 struct lttng_event_rule *rule,
382 const struct lttng_credentials *creds)
6d420eff
JR
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;
2b00d462 390 struct lttng_bytecode *bytecode = NULL;
6d420eff
JR
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(
58daac01 454 tracepoint->internal_filter.filter, creds,
6d420eff
JR
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
465error:
466end:
467 free(bytecode);
468 return ret_code;
469}
470
471static 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
2b00d462 482static const struct lttng_bytecode *
6d420eff
JR
483lttng_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
993578ff 494static enum lttng_event_rule_generate_exclusions_status
6d420eff 495lttng_event_rule_tracepoint_generate_exclusions(
993578ff
JR
496 const struct lttng_event_rule *rule,
497 struct lttng_event_exclusion **_exclusions)
6d420eff 498{
993578ff
JR
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;
6d420eff 504
993578ff
JR
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);
6d420eff
JR
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. */
993578ff
JR
517 exclusions = NULL;
518 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
6d420eff
JR
519 goto end;
520 case LTTNG_DOMAIN_UST:
521 /* Exclusions supported. */
522 break;
523 default:
993578ff 524 /* Unknown domain. */
6d420eff
JR
525 abort();
526 }
527
993578ff 528 event_rule_status = lttng_event_rule_tracepoint_get_exclusions_count(
6d420eff 529 rule, &nb_exclusions);
993578ff 530 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
6d420eff
JR
531 if (nb_exclusions == 0) {
532 /* Nothing to do. */
993578ff
JR
533 exclusions = NULL;
534 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
6d420eff
JR
535 goto end;
536 }
537
993578ff
JR
538 exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
539 (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
540 if (!exclusions) {
6d420eff 541 PERROR("Failed to allocate exclusions buffer");
993578ff 542 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY;
6d420eff
JR
543 goto end;
544 }
545
993578ff 546 exclusions->count = nb_exclusions;
6d420eff 547 for (i = 0; i < nb_exclusions; i++) {
993578ff
JR
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 }
6d420eff
JR
564 }
565
993578ff
JR
566 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK;
567
6d420eff 568end:
993578ff
JR
569 *_exclusions = exclusions;
570 return ret_status;
6d420eff
JR
571}
572
573static void destroy_lttng_exclusions_element(void *ptr)
574{
575 free(ptr);
576}
577
959e3c66
JR
578static 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
85b05318
JR
596 if (tp_rule->log_level_rule) {
597 hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule);
959e3c66
JR
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
44760c20
JR
616static 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;
85b05318
JR
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;
44760c20
JR
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
85b05318
JR
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;
44760c20
JR
680
681 event = local_event;
682 local_event = NULL;
683error:
684 free(local_event);
685 return event;
686}
687
6d420eff
JR
688struct 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;
cb6096aa 693 enum lttng_event_rule_status status;
6d420eff
JR
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;
959e3c66 718 tp_rule->parent.hash = lttng_event_rule_tracepoint_hash;
44760c20
JR
719 tp_rule->parent.generate_lttng_event =
720 lttng_event_rule_tracepoint_generate_lttng_event;
6d420eff
JR
721
722 tp_rule->domain = domain_type;
85b05318 723 tp_rule->log_level_rule = NULL;
6d420eff
JR
724
725 lttng_dynamic_pointer_array_init(&tp_rule->exclusions,
726 destroy_lttng_exclusions_element);
cb6096aa
JR
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
6d420eff
JR
735end:
736 return rule;
737}
738
739LTTNG_HIDDEN
740ssize_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;
6d420eff
JR
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;
85b05318 756 struct lttng_log_level_rule *log_level_rule = NULL;
6d420eff
JR
757
758 if (!_event_rule) {
759 ret = -1;
760 goto end;
761 }
762
3e6e0df2
JG
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)) {
6d420eff
JR
766 ERR("Failed to initialize from malformed event rule tracepoint: buffer too short to contain header.");
767 ret = -1;
768 goto end;
769 }
770
6d420eff
JR
771 tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data;
772
6d420eff
JR
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
6d420eff
JR
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);
3e6e0df2
JG
796
797 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
798 ret = -1;
799 goto end;
800 }
801
3e6e0df2 802 pattern = current_buffer_view.data;
6d420eff
JR
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);
3e6e0df2 819 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
820 ret = -1;
821 goto end;
822 }
823
3e6e0df2 824 filter_expression = current_buffer_view.data;
6d420eff
JR
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
835skip_filter_expression:
85b05318
JR
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
859skip_log_level_rule:
6d420eff
JR
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));
3e6e0df2 863 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
864 ret = -1;
865 goto end;
866 }
867
3e6e0df2 868 exclusion_len = (typeof(exclusion_len)) current_buffer_view.data;
6d420eff 869 offset += sizeof(*exclusion_len);
3e6e0df2 870
6d420eff
JR
871 current_buffer_view = lttng_buffer_view_from_view(
872 &view->buffer, offset, *exclusion_len);
3e6e0df2
JG
873 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
874 ret = -1;
875 goto end;
876 }
877
6d420eff
JR
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
85b05318
JR
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
6d420eff
JR
924 *_event_rule = rule;
925 rule = NULL;
926 ret = offset;
927end:
928 free(exclusions);
85b05318 929 lttng_log_level_rule_destroy(log_level_rule);
6d420eff
JR
930 lttng_event_rule_destroy(rule);
931 return ret;
932}
933
934enum 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;
959end:
960 return status;
961}
962
963enum 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;
982end:
983 return status;
984}
985
986enum 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;
1001end:
1002 return status;
1003}
1004
1005enum 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;
1033end:
1034 return status;
1035}
1036
1037enum 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;
1056end:
1057 return status;
1058}
1059
85b05318
JR
1060static bool log_level_rule_valid(const struct lttng_log_level_rule *rule,
1061 enum lttng_domain_type domain)
6d420eff
JR
1062{
1063 bool valid = false;
85b05318
JR
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);
6d420eff
JR
1080
1081 switch (domain) {
1082 case LTTNG_DOMAIN_KERNEL:
85b05318
JR
1083 valid = false;
1084 break;
6d420eff
JR
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
85b05318
JR
1102 * span the entire int32 range.
1103 *
6d420eff
JR
1104 * For python, custom log level are possible, it is not clear if
1105 * negative value are accepted (NOTSET == 0) but the source code
85b05318 1106 * validates against the int type implying that negative values
6d420eff
JR
1107 * are accepted.
1108 */
1109 valid = true;
1110 goto end;
6d420eff
JR
1111 case LTTNG_DOMAIN_NONE:
1112 default:
1113 abort();
1114 }
1115
1116end:
1117 return valid;
1118}
1119
85b05318
JR
1120enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_rule(
1121 struct lttng_event_rule *rule,
1122 const struct lttng_log_level_rule *log_level_rule)
6d420eff
JR
1123{
1124 struct lttng_event_rule_tracepoint *tracepoint;
1125 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
85b05318 1126 struct lttng_log_level_rule *copy = NULL;
6d420eff
JR
1127
1128 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1129 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1130 goto end;
1131 }
1132
1133 tracepoint = container_of(
1134 rule, struct lttng_event_rule_tracepoint, parent);
1135
85b05318 1136 if (!log_level_rule_valid(log_level_rule, tracepoint->domain)) {
6d420eff
JR
1137 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1138 goto end;
1139 }
1140
85b05318
JR
1141 copy = lttng_log_level_rule_copy(log_level_rule);
1142 if (copy == NULL) {
1143 status = LTTNG_EVENT_RULE_STATUS_ERROR;
6d420eff
JR
1144 goto end;
1145 }
1146
85b05318
JR
1147 if (tracepoint->log_level_rule) {
1148 lttng_log_level_rule_destroy(tracepoint->log_level_rule);
6d420eff
JR
1149 }
1150
85b05318 1151 tracepoint->log_level_rule = copy;
6d420eff 1152
6d420eff
JR
1153end:
1154 return status;
1155}
1156
85b05318 1157enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_rule(
6d420eff 1158 const struct lttng_event_rule *rule,
85b05318
JR
1159 const struct lttng_log_level_rule **log_level_rule
1160 )
6d420eff
JR
1161{
1162 struct lttng_event_rule_tracepoint *tracepoint;
1163 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1164
85b05318 1165 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !log_level_rule) {
6d420eff
JR
1166 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1167 goto end;
1168 }
1169
1170 tracepoint = container_of(
1171 rule, struct lttng_event_rule_tracepoint, parent);
85b05318 1172 if (tracepoint->log_level_rule == NULL) {
6d420eff
JR
1173 status = LTTNG_EVENT_RULE_STATUS_UNSET;
1174 goto end;
1175 }
1176
85b05318 1177 *log_level_rule = tracepoint->log_level_rule;
6d420eff
JR
1178end:
1179 return status;
1180}
1181
1182enum lttng_event_rule_status lttng_event_rule_tracepoint_add_exclusion(
1183 struct lttng_event_rule *rule,
1184 const char *exclusion)
1185{
1186 int ret;
1187 char *exclusion_copy = NULL;
1188 struct lttng_event_rule_tracepoint *tracepoint;
1189 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1190 enum lttng_domain_type domain_type;
1191
1192 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) ||
1193 !exclusion) {
1194 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1195 goto end;
1196 }
1197
1198 tracepoint = container_of(
1199 rule, struct lttng_event_rule_tracepoint, parent);
1200
1201 status = lttng_event_rule_tracepoint_get_domain_type(
1202 rule, &domain_type);
1203 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
1204 goto end;
1205 }
1206
1207 switch (domain_type) {
1208 case LTTNG_DOMAIN_KERNEL:
1209 case LTTNG_DOMAIN_JUL:
1210 case LTTNG_DOMAIN_LOG4J:
1211 case LTTNG_DOMAIN_PYTHON:
1212 status = LTTNG_EVENT_RULE_STATUS_UNSUPPORTED;
1213 goto end;
1214 case LTTNG_DOMAIN_UST:
1215 /* Exclusions supported. */
1216 break;
1217 default:
1218 abort();
1219 }
1220
1221 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
1222 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1223 goto end;
1224 }
1225
1226 exclusion_copy = strdup(exclusion);
1227 if (!exclusion_copy) {
1228 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1229 goto end;
1230 }
1231
1232 ret = lttng_dynamic_pointer_array_add_pointer(&tracepoint->exclusions,
1233 exclusion_copy);
1234 if (ret < 0) {
1235 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1236 goto end;
1237 }
1238
1239 exclusion_copy = NULL;
1240end:
1241 free(exclusion_copy);
1242 return status;
1243}
1244
1245enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusions_count(
1246 const struct lttng_event_rule *rule, unsigned int *count)
1247{
1248 struct lttng_event_rule_tracepoint *tracepoint;
1249 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1250
1251 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !count) {
1252 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1253 goto end;
1254 }
1255
1256 tracepoint = container_of(
1257 rule, struct lttng_event_rule_tracepoint, parent);
1258 *count = lttng_dynamic_pointer_array_get_count(&tracepoint->exclusions);
1259end:
1260 return status;
1261}
1262
1263enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusion_at_index(
1264 const struct lttng_event_rule *rule,
1265 unsigned int index,
1266 const char **exclusion)
1267{
1268 unsigned int count;
1269 struct lttng_event_rule_tracepoint *tracepoint;
1270 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1271
1272 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !exclusion) {
1273 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1274 goto end;
1275 }
1276
1277 tracepoint = container_of(
1278 rule, struct lttng_event_rule_tracepoint, parent);
1279 if (lttng_event_rule_tracepoint_get_exclusions_count(rule, &count) !=
1280 LTTNG_EVENT_RULE_STATUS_OK) {
1281 goto end;
1282 }
1283
1284 if (index >= count) {
1285 goto end;
1286 }
1287
1288 *exclusion = lttng_dynamic_pointer_array_get_pointer(
1289 &tracepoint->exclusions, index);
1290end:
1291 return status;
1292}
This page took 0.075818 seconds and 4 git commands to generate.