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