2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/credentials.h>
9 #include <common/error.h>
10 #include <common/hashtable/hashtable.h>
11 #include <common/hashtable/utils.h>
12 #include <common/macros.h>
13 #include <common/mi-lttng.h>
14 #include <common/optional.h>
15 #include <common/payload-view.h>
16 #include <common/payload.h>
17 #include <common/runas.h>
18 #include <common/string-utils/string-utils.h>
19 #include <lttng/event-rule/event-rule-internal.h>
20 #include <lttng/event-rule/kernel-tracepoint-internal.h>
21 #include <lttng/event.h>
23 #define IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) \
24 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT)
26 static void lttng_event_rule_kernel_tracepoint_destroy(struct lttng_event_rule
*rule
)
28 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
34 tracepoint
= container_of(
35 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
37 free(tracepoint
->pattern
);
38 free(tracepoint
->filter_expression
);
39 free(tracepoint
->internal_filter
.filter
);
40 free(tracepoint
->internal_filter
.bytecode
);
44 static bool lttng_event_rule_kernel_tracepoint_validate(
45 const struct lttng_event_rule
*rule
)
48 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
54 tracepoint
= container_of(
55 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
58 if (!tracepoint
->pattern
) {
59 ERR("Invalid kernel tracepoint event rule: a pattern must be set.");
68 static int lttng_event_rule_kernel_tracepoint_serialize(
69 const struct lttng_event_rule
*rule
,
70 struct lttng_payload
*payload
)
73 size_t pattern_len
, filter_expression_len
;
74 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
75 struct lttng_event_rule_kernel_tracepoint_comm tracepoint_comm
;
77 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
)) {
82 DBG("Serializing kernel tracepoint event rule.");
83 tracepoint
= container_of(
84 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
86 pattern_len
= strlen(tracepoint
->pattern
) + 1;
88 if (tracepoint
->filter_expression
!= NULL
) {
89 filter_expression_len
=
90 strlen(tracepoint
->filter_expression
) + 1;
92 filter_expression_len
= 0;
95 tracepoint_comm
.pattern_len
= pattern_len
;
96 tracepoint_comm
.filter_expression_len
= filter_expression_len
;
98 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &tracepoint_comm
,
99 sizeof(tracepoint_comm
));
104 ret
= lttng_dynamic_buffer_append(
105 &payload
->buffer
, tracepoint
->pattern
, pattern_len
);
110 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, tracepoint
->filter_expression
,
111 filter_expression_len
);
120 static bool lttng_event_rule_kernel_tracepoint_is_equal(
121 const struct lttng_event_rule
*_a
,
122 const struct lttng_event_rule
*_b
)
124 bool is_equal
= false;
125 struct lttng_event_rule_kernel_tracepoint
*a
, *b
;
127 a
= container_of(_a
, struct lttng_event_rule_kernel_tracepoint
, parent
);
128 b
= container_of(_b
, struct lttng_event_rule_kernel_tracepoint
, parent
);
130 if (!!a
->filter_expression
!= !!b
->filter_expression
) {
135 LTTNG_ASSERT(a
->pattern
);
136 LTTNG_ASSERT(b
->pattern
);
137 if (strcmp(a
->pattern
, b
->pattern
)) {
141 if (a
->filter_expression
&& b
->filter_expression
) {
142 if (strcmp(a
->filter_expression
, b
->filter_expression
)) {
145 } else if (!!a
->filter_expression
!= !!b
->filter_expression
) {
146 /* One is set; not the other. */
155 static enum lttng_error_code
156 lttng_event_rule_kernel_tracepoint_generate_filter_bytecode(
157 struct lttng_event_rule
*rule
,
158 const struct lttng_credentials
*creds
)
161 enum lttng_error_code ret_code
;
162 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
163 enum lttng_event_rule_status status
;
165 struct lttng_bytecode
*bytecode
= NULL
;
169 tracepoint
= container_of(
170 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
172 status
= lttng_event_rule_kernel_tracepoint_get_filter(rule
, &filter
);
173 if (status
== LTTNG_EVENT_RULE_STATUS_UNSET
) {
175 } else if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
176 ret_code
= LTTNG_ERR_FILTER_INVAL
;
180 if (filter
&& filter
[0] == '\0') {
181 ret_code
= LTTNG_ERR_FILTER_INVAL
;
186 tracepoint
->internal_filter
.filter
= strdup(filter
);
187 if (tracepoint
->internal_filter
.filter
== NULL
) {
188 ret_code
= LTTNG_ERR_NOMEM
;
192 tracepoint
->internal_filter
.filter
= NULL
;
195 if (tracepoint
->internal_filter
.filter
== NULL
) {
200 ret
= run_as_generate_filter_bytecode(
201 tracepoint
->internal_filter
.filter
, creds
,
204 ret_code
= LTTNG_ERR_FILTER_INVAL
;
208 tracepoint
->internal_filter
.bytecode
= bytecode
;
218 static const char *lttng_event_rule_kernel_tracepoint_get_internal_filter(
219 const struct lttng_event_rule
*rule
)
221 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
224 tracepoint
= container_of(
225 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
226 return tracepoint
->internal_filter
.filter
;
229 static const struct lttng_bytecode
*
230 lttng_event_rule_kernel_tracepoint_get_internal_filter_bytecode(
231 const struct lttng_event_rule
*rule
)
233 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
236 tracepoint
= container_of(
237 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
238 return tracepoint
->internal_filter
.bytecode
;
241 static enum lttng_event_rule_generate_exclusions_status
242 lttng_event_rule_kernel_tracepoint_generate_exclusions(
243 const struct lttng_event_rule
*rule
,
244 struct lttng_event_exclusion
**_exclusions
)
248 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE
;
251 static unsigned long lttng_event_rule_kernel_tracepoint_hash(
252 const struct lttng_event_rule
*rule
)
255 struct lttng_event_rule_kernel_tracepoint
*tp_rule
=
256 container_of(rule
, typeof(*tp_rule
), parent
);
258 hash
= hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT
,
260 hash
^= hash_key_str(tp_rule
->pattern
, lttng_ht_seed
);
262 if (tp_rule
->filter_expression
) {
263 hash
^= hash_key_str(tp_rule
->filter_expression
, lttng_ht_seed
);
269 static enum lttng_error_code
lttng_event_rule_kernel_tracepoint_mi_serialize(
270 const struct lttng_event_rule
*rule
, struct mi_writer
*writer
)
273 enum lttng_error_code ret_code
;
274 enum lttng_event_rule_status status
;
275 const char *filter
= NULL
;
276 const char *name_pattern
= NULL
;
279 LTTNG_ASSERT(writer
);
280 LTTNG_ASSERT(IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
));
282 status
= lttng_event_rule_kernel_tracepoint_get_name_pattern(
283 rule
, &name_pattern
);
284 LTTNG_ASSERT(status
== LTTNG_EVENT_RULE_STATUS_OK
);
285 LTTNG_ASSERT(name_pattern
);
287 status
= lttng_event_rule_kernel_tracepoint_get_filter(rule
, &filter
);
288 LTTNG_ASSERT(status
== LTTNG_EVENT_RULE_STATUS_OK
||
289 status
== LTTNG_EVENT_RULE_STATUS_UNSET
);
291 /* Open event rule kernel tracepoint element. */
292 ret
= mi_lttng_writer_open_element(
293 writer
, mi_lttng_element_event_rule_kernel_tracepoint
);
299 ret
= mi_lttng_writer_write_element_string(writer
,
300 mi_lttng_element_event_rule_name_pattern
, name_pattern
);
306 if (filter
!= NULL
) {
307 ret
= mi_lttng_writer_write_element_string(writer
,
308 mi_lttng_element_event_rule_filter_expression
,
315 /* Close event rule kernel tracepoint element. */
316 ret
= mi_lttng_writer_close_element(writer
);
325 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
330 struct lttng_event_rule
*lttng_event_rule_kernel_tracepoint_create(void)
332 struct lttng_event_rule
*rule
= NULL
;
333 struct lttng_event_rule_kernel_tracepoint
*tp_rule
;
334 enum lttng_event_rule_status status
;
336 tp_rule
= zmalloc(sizeof(struct lttng_event_rule_kernel_tracepoint
));
341 rule
= &tp_rule
->parent
;
342 lttng_event_rule_init(&tp_rule
->parent
, LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT
);
343 tp_rule
->parent
.validate
= lttng_event_rule_kernel_tracepoint_validate
;
344 tp_rule
->parent
.serialize
= lttng_event_rule_kernel_tracepoint_serialize
;
345 tp_rule
->parent
.equal
= lttng_event_rule_kernel_tracepoint_is_equal
;
346 tp_rule
->parent
.destroy
= lttng_event_rule_kernel_tracepoint_destroy
;
347 tp_rule
->parent
.generate_filter_bytecode
=
348 lttng_event_rule_kernel_tracepoint_generate_filter_bytecode
;
349 tp_rule
->parent
.get_filter
=
350 lttng_event_rule_kernel_tracepoint_get_internal_filter
;
351 tp_rule
->parent
.get_filter_bytecode
=
352 lttng_event_rule_kernel_tracepoint_get_internal_filter_bytecode
;
353 tp_rule
->parent
.generate_exclusions
=
354 lttng_event_rule_kernel_tracepoint_generate_exclusions
;
355 tp_rule
->parent
.hash
= lttng_event_rule_kernel_tracepoint_hash
;
356 tp_rule
->parent
.mi_serialize
= lttng_event_rule_kernel_tracepoint_mi_serialize
;
358 /* Not necessary for now. */
359 tp_rule
->parent
.generate_lttng_event
= NULL
;
361 /* Default pattern is '*'. */
362 status
= lttng_event_rule_kernel_tracepoint_set_name_pattern(rule
, "*");
363 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
364 lttng_event_rule_destroy(rule
);
373 ssize_t
lttng_event_rule_kernel_tracepoint_create_from_payload(
374 struct lttng_payload_view
*view
,
375 struct lttng_event_rule
**_event_rule
)
377 ssize_t ret
, offset
= 0;
378 enum lttng_event_rule_status status
;
379 const struct lttng_event_rule_kernel_tracepoint_comm
*tracepoint_comm
;
381 const char *filter_expression
= NULL
;
382 struct lttng_buffer_view current_buffer_view
;
383 struct lttng_event_rule
*rule
= NULL
;
390 current_buffer_view
= lttng_buffer_view_from_view(
391 &view
->buffer
, offset
, sizeof(*tracepoint_comm
));
392 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
393 ERR("Failed to initialize from malformed event rule kernel tracepoint: buffer too short to contain header.");
398 tracepoint_comm
= (typeof(tracepoint_comm
)) current_buffer_view
.data
;
400 /* Skip to payload. */
401 offset
+= current_buffer_view
.size
;
403 /* Map the pattern. */
404 current_buffer_view
= lttng_buffer_view_from_view(
405 &view
->buffer
, offset
, tracepoint_comm
->pattern_len
);
407 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
412 pattern
= current_buffer_view
.data
;
413 if (!lttng_buffer_view_contains_string(¤t_buffer_view
, pattern
,
414 tracepoint_comm
->pattern_len
)) {
419 /* Skip after the pattern. */
420 offset
+= tracepoint_comm
->pattern_len
;
422 if (!tracepoint_comm
->filter_expression_len
) {
423 goto skip_filter_expression
;
426 /* Map the filter_expression. */
427 current_buffer_view
= lttng_buffer_view_from_view(&view
->buffer
, offset
,
428 tracepoint_comm
->filter_expression_len
);
429 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
434 filter_expression
= current_buffer_view
.data
;
435 if (!lttng_buffer_view_contains_string(¤t_buffer_view
,
437 tracepoint_comm
->filter_expression_len
)) {
442 /* Skip after the pattern. */
443 offset
+= tracepoint_comm
->filter_expression_len
;
445 skip_filter_expression
:
447 rule
= lttng_event_rule_kernel_tracepoint_create();
449 ERR("Failed to create event rule kernel tracepoint.");
454 status
= lttng_event_rule_kernel_tracepoint_set_name_pattern(rule
, pattern
);
455 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
456 ERR("Failed to set event rule kernel tracepoint pattern.");
461 if (filter_expression
) {
462 status
= lttng_event_rule_kernel_tracepoint_set_filter(
463 rule
, filter_expression
);
464 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
465 ERR("Failed to set event rule kernel tracepoint pattern.");
475 lttng_event_rule_destroy(rule
);
479 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_name_pattern(
480 struct lttng_event_rule
*rule
, const char *pattern
)
482 char *pattern_copy
= NULL
;
483 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
484 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
486 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
||
487 strlen(pattern
) == 0) {
488 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
492 tracepoint
= container_of(
493 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
494 pattern_copy
= strdup(pattern
);
496 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
500 /* Normalize the pattern. */
501 strutils_normalize_star_glob_pattern(pattern_copy
);
503 free(tracepoint
->pattern
);
505 tracepoint
->pattern
= pattern_copy
;
511 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_name_pattern(
512 const struct lttng_event_rule
*rule
, const char **pattern
)
514 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
515 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
517 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
) {
518 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
522 tracepoint
= container_of(
523 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
524 if (!tracepoint
->pattern
) {
525 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
529 *pattern
= tracepoint
->pattern
;
534 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_filter(
535 struct lttng_event_rule
*rule
, const char *expression
)
537 char *expression_copy
= NULL
;
538 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
539 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
541 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
||
542 strlen(expression
) == 0) {
543 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
547 tracepoint
= container_of(
548 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
549 expression_copy
= strdup(expression
);
550 if (!expression_copy
) {
551 PERROR("Failed to copy filter expression");
552 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
556 if (tracepoint
->filter_expression
) {
557 free(tracepoint
->filter_expression
);
560 tracepoint
->filter_expression
= expression_copy
;
561 expression_copy
= NULL
;
566 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_filter(
567 const struct lttng_event_rule
*rule
, const char **expression
)
569 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
570 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
572 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
) {
573 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
577 tracepoint
= container_of(
578 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
579 if (!tracepoint
->filter_expression
) {
580 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
584 *expression
= tracepoint
->filter_expression
;