2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/credentials.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/optional.h>
13 #include <common/payload.h>
14 #include <common/payload-view.h>
15 #include <common/runas.h>
16 #include <common/hashtable/hashtable.h>
17 #include <common/hashtable/utils.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
) {
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 struct lttng_event_rule
*lttng_event_rule_kernel_tracepoint_create(void)
271 struct lttng_event_rule
*rule
= NULL
;
272 struct lttng_event_rule_kernel_tracepoint
*tp_rule
;
273 enum lttng_event_rule_status status
;
275 tp_rule
= zmalloc(sizeof(struct lttng_event_rule_kernel_tracepoint
));
280 rule
= &tp_rule
->parent
;
281 lttng_event_rule_init(&tp_rule
->parent
, LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT
);
282 tp_rule
->parent
.validate
= lttng_event_rule_kernel_tracepoint_validate
;
283 tp_rule
->parent
.serialize
= lttng_event_rule_kernel_tracepoint_serialize
;
284 tp_rule
->parent
.equal
= lttng_event_rule_kernel_tracepoint_is_equal
;
285 tp_rule
->parent
.destroy
= lttng_event_rule_kernel_tracepoint_destroy
;
286 tp_rule
->parent
.generate_filter_bytecode
=
287 lttng_event_rule_kernel_tracepoint_generate_filter_bytecode
;
288 tp_rule
->parent
.get_filter
=
289 lttng_event_rule_kernel_tracepoint_get_internal_filter
;
290 tp_rule
->parent
.get_filter_bytecode
=
291 lttng_event_rule_kernel_tracepoint_get_internal_filter_bytecode
;
292 tp_rule
->parent
.generate_exclusions
=
293 lttng_event_rule_kernel_tracepoint_generate_exclusions
;
294 tp_rule
->parent
.hash
= lttng_event_rule_kernel_tracepoint_hash
;
296 /* Not necessary for now. */
297 tp_rule
->parent
.generate_lttng_event
= NULL
;
299 /* Default pattern is '*'. */
300 status
= lttng_event_rule_kernel_tracepoint_set_name_pattern(rule
, "*");
301 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
302 lttng_event_rule_destroy(rule
);
311 ssize_t
lttng_event_rule_kernel_tracepoint_create_from_payload(
312 struct lttng_payload_view
*view
,
313 struct lttng_event_rule
**_event_rule
)
315 ssize_t ret
, offset
= 0;
316 enum lttng_event_rule_status status
;
317 const struct lttng_event_rule_kernel_tracepoint_comm
*tracepoint_comm
;
319 const char *filter_expression
= NULL
;
320 struct lttng_buffer_view current_buffer_view
;
321 struct lttng_event_rule
*rule
= NULL
;
328 current_buffer_view
= lttng_buffer_view_from_view(
329 &view
->buffer
, offset
, sizeof(*tracepoint_comm
));
330 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
331 ERR("Failed to initialize from malformed event rule kernel tracepoint: buffer too short to contain header.");
336 tracepoint_comm
= (typeof(tracepoint_comm
)) current_buffer_view
.data
;
338 /* Skip to payload. */
339 offset
+= current_buffer_view
.size
;
341 /* Map the pattern. */
342 current_buffer_view
= lttng_buffer_view_from_view(
343 &view
->buffer
, offset
, tracepoint_comm
->pattern_len
);
345 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
350 pattern
= current_buffer_view
.data
;
351 if (!lttng_buffer_view_contains_string(¤t_buffer_view
, pattern
,
352 tracepoint_comm
->pattern_len
)) {
357 /* Skip after the pattern. */
358 offset
+= tracepoint_comm
->pattern_len
;
360 if (!tracepoint_comm
->filter_expression_len
) {
361 goto skip_filter_expression
;
364 /* Map the filter_expression. */
365 current_buffer_view
= lttng_buffer_view_from_view(&view
->buffer
, offset
,
366 tracepoint_comm
->filter_expression_len
);
367 if (!lttng_buffer_view_is_valid(¤t_buffer_view
)) {
372 filter_expression
= current_buffer_view
.data
;
373 if (!lttng_buffer_view_contains_string(¤t_buffer_view
,
375 tracepoint_comm
->filter_expression_len
)) {
380 /* Skip after the pattern. */
381 offset
+= tracepoint_comm
->filter_expression_len
;
383 skip_filter_expression
:
385 rule
= lttng_event_rule_kernel_tracepoint_create();
387 ERR("Failed to create event rule kernel tracepoint.");
392 status
= lttng_event_rule_kernel_tracepoint_set_name_pattern(rule
, pattern
);
393 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
394 ERR("Failed to set event rule kernel tracepoint pattern.");
399 if (filter_expression
) {
400 status
= lttng_event_rule_kernel_tracepoint_set_filter(
401 rule
, filter_expression
);
402 if (status
!= LTTNG_EVENT_RULE_STATUS_OK
) {
403 ERR("Failed to set event rule kernel tracepoint pattern.");
413 lttng_event_rule_destroy(rule
);
417 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_name_pattern(
418 struct lttng_event_rule
*rule
, const char *pattern
)
420 char *pattern_copy
= NULL
;
421 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
422 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
424 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
||
425 strlen(pattern
) == 0) {
426 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
430 tracepoint
= container_of(
431 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
432 pattern_copy
= strdup(pattern
);
434 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
438 /* Normalize the pattern. */
439 strutils_normalize_star_glob_pattern(pattern_copy
);
441 free(tracepoint
->pattern
);
443 tracepoint
->pattern
= pattern_copy
;
449 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_name_pattern(
450 const struct lttng_event_rule
*rule
, const char **pattern
)
452 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
453 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
455 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !pattern
) {
456 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
460 tracepoint
= container_of(
461 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
462 if (!tracepoint
->pattern
) {
463 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
467 *pattern
= tracepoint
->pattern
;
472 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_set_filter(
473 struct lttng_event_rule
*rule
, const char *expression
)
475 char *expression_copy
= NULL
;
476 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
477 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
479 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
||
480 strlen(expression
) == 0) {
481 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
485 tracepoint
= container_of(
486 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
487 expression_copy
= strdup(expression
);
488 if (!expression_copy
) {
489 PERROR("Failed to copy filter expression");
490 status
= LTTNG_EVENT_RULE_STATUS_ERROR
;
494 if (tracepoint
->filter_expression
) {
495 free(tracepoint
->filter_expression
);
498 tracepoint
->filter_expression
= expression_copy
;
499 expression_copy
= NULL
;
504 enum lttng_event_rule_status
lttng_event_rule_kernel_tracepoint_get_filter(
505 const struct lttng_event_rule
*rule
, const char **expression
)
507 struct lttng_event_rule_kernel_tracepoint
*tracepoint
;
508 enum lttng_event_rule_status status
= LTTNG_EVENT_RULE_STATUS_OK
;
510 if (!rule
|| !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule
) || !expression
) {
511 status
= LTTNG_EVENT_RULE_STATUS_INVALID
;
515 tracepoint
= container_of(
516 rule
, struct lttng_event_rule_kernel_tracepoint
, parent
);
517 if (!tracepoint
->filter_expression
) {
518 status
= LTTNG_EVENT_RULE_STATUS_UNSET
;
522 *expression
= tracepoint
->filter_expression
;