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