2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/credentials.hpp>
9 #include <common/error.hpp>
10 #include <common/hashtable/hashtable.hpp>
11 #include <common/hashtable/utils.hpp>
12 #include <common/macros.hpp>
13 #include <common/mi-lttng.hpp>
14 #include <common/optional.hpp>
15 #include <common/payload-view.hpp>
16 #include <common/payload.hpp>
17 #include <common/runas.hpp>
18 #include <common/string-utils/string-utils.hpp>
19 #include <lttng/event-rule/event-rule-internal.hpp>
20 #include <lttng/event-rule/kernel-tracepoint-internal.hpp>
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
= lttng::utils::container_of(
35 rule
, <tng_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
= lttng::utils::container_of(
55 rule
, <tng_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
= lttng::utils::container_of(
84 rule
, <tng_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
= lttng::utils::container_of(_a
, <tng_event_rule_kernel_tracepoint::parent
);
128 b
= lttng::utils::container_of(_b
, <tng_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
= lttng::utils::container_of(
170 rule
, <tng_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
= lttng::utils::container_of(
225 rule
, <tng_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
= lttng::utils::container_of(
237 rule
, <tng_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
__attribute__((unused
)),
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
= lttng::utils::container_of(
256 rule
, <tng_event_rule_kernel_tracepoint::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
<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
);
372 ssize_t
lttng_event_rule_kernel_tracepoint_create_from_payload(
373 struct lttng_payload_view
*view
,
374 struct lttng_event_rule
**_event_rule
)
376 ssize_t ret
, offset
= 0;
377 enum lttng_event_rule_status status
;
378 const struct lttng_event_rule_kernel_tracepoint_comm
*tracepoint_comm
;
380 const char *filter_expression
= NULL
;
381 struct lttng_buffer_view current_buffer_view
;
382 struct lttng_event_rule
*rule
= NULL
;
389 current_buffer_view
= lttng_buffer_view_from_view(
390 &view
->buffer
, offset
, sizeof(*tracepoint_comm
));
391 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
392 ERR("Failed to initialize from malformed event rule kernel tracepoint: buffer too short to contain header.");
397 tracepoint_comm
= (typeof(tracepoint_comm
)) current_buffer_view
.data
;
399 /* Skip to payload. */
400 offset
+= current_buffer_view
.size
;
402 /* Map the pattern. */
403 current_buffer_view
= lttng_buffer_view_from_view(
404 &view
->buffer
, offset
, tracepoint_comm
->pattern_len
);
406 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
411 pattern
= current_buffer_view
.data
;
412 if (!lttng_buffer_view_contains_string(¤t_buffer_view
, pattern
,
413 tracepoint_comm
->pattern_len
)) {
418 /* Skip after the pattern. */
419 offset
+= tracepoint_comm
->pattern_len
;
421 if (!tracepoint_comm
->filter_expression_len
) {
422 goto skip_filter_expression
;
425 /* Map the filter_expression. */
426 current_buffer_view
= lttng_buffer_view_from_view(&view
->buffer
, offset
,
427 tracepoint_comm
->filter_expression_len
);
428 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
433 filter_expression
= current_buffer_view
.data
;
434 if (!lttng_buffer_view_contains_string(¤t_buffer_view
,
436 tracepoint_comm
->filter_expression_len
)) {
441 /* Skip after the pattern. */
442 offset
+= tracepoint_comm
->filter_expression_len
;
444 skip_filter_expression
:
446 rule
= lttng_event_rule_kernel_tracepoint_create();
448 ERR("Failed to create event rule kernel tracepoint.");
453 status
= lttng_event_rule_kernel_tracepoint_set_name_pattern(rule
, pattern
);
454 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
455 ERR("Failed to set event rule kernel tracepoint pattern.");
460 if (filter_expression
) {
461 status
= lttng_event_rule_kernel_tracepoint_set_filter(
462 rule
, filter_expression
);
463 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
464 ERR("Failed to set event rule kernel tracepoint pattern.");
474 lttng_event_rule_destroy(rule
);
478 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_name_pattern(
479 struct lttng_event_rule
*rule
, const char *pattern
)
481 char *pattern_copy
= NULL
;
482 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
483 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
485 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
||
486 strlen(pattern
) == 0) {
487 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
491 tracepoint
= lttng::utils::container_of(
492 rule
, <tng_event_rule_kernel_tracepoint::parent
);
493 pattern_copy
= strdup(pattern
);
495 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
499 /* Normalize the pattern. */
500 strutils_normalize_star_glob_pattern(pattern_copy
);
502 free(tracepoint
->pattern
);
504 tracepoint
->pattern
= pattern_copy
;
510 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_name_pattern(
511 const struct lttng_event_rule
*rule
, const char **pattern
)
513 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
514 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
516 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
) {
517 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
521 tracepoint
= lttng::utils::container_of(
522 rule
, <tng_event_rule_kernel_tracepoint::parent
);
523 if (!tracepoint
->pattern
) {
524 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
528 *pattern
= tracepoint
->pattern
;
533 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_filter(
534 struct lttng_event_rule
*rule
, const char *expression
)
536 char *expression_copy
= NULL
;
537 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
538 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
540 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
||
541 strlen(expression
) == 0) {
542 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
546 tracepoint
= lttng::utils::container_of(
547 rule
, <tng_event_rule_kernel_tracepoint::parent
);
548 expression_copy
= strdup(expression
);
549 if (!expression_copy
) {
550 PERROR("Failed to copy filter expression");
551 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
555 if (tracepoint
->filter_expression
) {
556 free(tracepoint
->filter_expression
);
559 tracepoint
->filter_expression
= expression_copy
;
560 expression_copy
= NULL
;
565 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_filter(
566 const struct lttng_event_rule
*rule
, const char **expression
)
568 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
569 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
571 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
) {
572 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
576 tracepoint
= lttng::utils::container_of(
577 rule
, <tng_event_rule_kernel_tracepoint::parent
);
578 if (!tracepoint
->filter_expression
) {
579 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
583 *expression
= tracepoint
->filter_expression
;