Move event-expr-to-bytecode to event-expr
[lttng-tools.git] / src / common / event-rule / kernel-tracepoint.c
CommitLineData
af0818ef
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>
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>
22
23#define IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) \
24 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT)
25
26static void lttng_event_rule_kernel_tracepoint_destroy(struct lttng_event_rule *rule)
27{
28 struct lttng_event_rule_kernel_tracepoint *tracepoint;
29
30 if (rule == NULL) {
31 return;
32 }
33
34 tracepoint = container_of(
35 rule, struct lttng_event_rule_kernel_tracepoint, parent);
36
37 free(tracepoint->pattern);
38 free(tracepoint->filter_expression);
39 free(tracepoint->internal_filter.filter);
40 free(tracepoint->internal_filter.bytecode);
41 free(tracepoint);
42}
43
44static bool lttng_event_rule_kernel_tracepoint_validate(
45 const struct lttng_event_rule *rule)
46{
47 bool valid = false;
48 struct lttng_event_rule_kernel_tracepoint *tracepoint;
49
50 if (!rule) {
51 goto end;
52 }
53
54 tracepoint = container_of(
55 rule, struct lttng_event_rule_kernel_tracepoint, parent);
56
57 /* Required field. */
58 if (!tracepoint->pattern) {
59 ERR("Invalid kernel tracepoint event rule: a pattern must be set.");
60 goto end;
61 }
62
63 valid = true;
64end:
65 return valid;
66}
67
68static int lttng_event_rule_kernel_tracepoint_serialize(
69 const struct lttng_event_rule *rule,
70 struct lttng_payload *payload)
71{
72 int ret;
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;
76
77 if (!rule || !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule)) {
78 ret = -1;
79 goto end;
80 }
81
82 DBG("Serializing kernel tracepoint event rule.");
83 tracepoint = container_of(
84 rule, struct lttng_event_rule_kernel_tracepoint, parent);
85
86 pattern_len = strlen(tracepoint->pattern) + 1;
87
88 if (tracepoint->filter_expression != NULL) {
89 filter_expression_len =
90 strlen(tracepoint->filter_expression) + 1;
91 } else {
92 filter_expression_len = 0;
93 }
94
95 tracepoint_comm.pattern_len = pattern_len;
96 tracepoint_comm.filter_expression_len = filter_expression_len;
97
98 ret = lttng_dynamic_buffer_append(&payload->buffer, &tracepoint_comm,
99 sizeof(tracepoint_comm));
100 if (ret) {
101 goto end;
102 }
103
104 ret = lttng_dynamic_buffer_append(
105 &payload->buffer, tracepoint->pattern, pattern_len);
106 if (ret) {
107 goto end;
108 }
109
110 ret = lttng_dynamic_buffer_append(&payload->buffer, tracepoint->filter_expression,
111 filter_expression_len);
112 if (ret) {
113 goto end;
114 }
115
116end:
117 return ret;
118}
119
120static bool lttng_event_rule_kernel_tracepoint_is_equal(
121 const struct lttng_event_rule *_a,
122 const struct lttng_event_rule *_b)
123{
124 bool is_equal = false;
125 struct lttng_event_rule_kernel_tracepoint *a, *b;
126
127 a = container_of(_a, struct lttng_event_rule_kernel_tracepoint, parent);
128 b = container_of(_b, struct lttng_event_rule_kernel_tracepoint, parent);
129
130 if (!!a->filter_expression != !!b->filter_expression) {
131 goto end;
132 }
133
134 /* Long check. */
135 assert(a->pattern);
136 assert(b->pattern);
137 if (strcmp(a->pattern, b->pattern)) {
138 goto end;
139 }
140
141 if (a->filter_expression && b->filter_expression) {
142 if (strcmp(a->filter_expression, b->filter_expression)) {
143 goto end;
144 }
145 } else if (!!a->filter_expression != !!b->filter_expression) {
146 /* One is set; not the other. */
147 goto end;
148 }
149
150 is_equal = true;
151end:
152 return is_equal;
153}
154
155static enum lttng_error_code
156lttng_event_rule_kernel_tracepoint_generate_filter_bytecode(
157 struct lttng_event_rule *rule,
158 const struct lttng_credentials *creds)
159{
160 int ret;
161 enum lttng_error_code ret_code;
162 struct lttng_event_rule_kernel_tracepoint *tracepoint;
163 enum lttng_event_rule_status status;
164 const char *filter;
165 struct lttng_bytecode *bytecode = NULL;
166
167 assert(rule);
168
169 tracepoint = container_of(
170 rule, struct lttng_event_rule_kernel_tracepoint, parent);
171
172 status = lttng_event_rule_kernel_tracepoint_get_filter(rule, &filter);
173 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
174 filter = NULL;
175 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
176 ret_code = LTTNG_ERR_FILTER_INVAL;
177 goto end;
178 }
179
180 if (filter && filter[0] == '\0') {
181 ret_code = LTTNG_ERR_FILTER_INVAL;
182 goto error;
183 }
184
185 if (filter) {
186 tracepoint->internal_filter.filter = strdup(filter);
187 if (tracepoint->internal_filter.filter == NULL) {
188 ret_code = LTTNG_ERR_NOMEM;
189 goto error;
190 }
191 } else {
192 tracepoint->internal_filter.filter = NULL;
193 }
194
195 if (tracepoint->internal_filter.filter == NULL) {
196 ret_code = LTTNG_OK;
197 goto end;
198 }
199
200 ret = run_as_generate_filter_bytecode(
201 tracepoint->internal_filter.filter, creds,
202 &bytecode);
203 if (ret) {
204 ret_code = LTTNG_ERR_FILTER_INVAL;
205 goto end;
206 }
207
208 tracepoint->internal_filter.bytecode = bytecode;
209 bytecode = NULL;
210 ret_code = LTTNG_OK;
211
212error:
213end:
214 free(bytecode);
215 return ret_code;
216}
217
218static const char *lttng_event_rule_kernel_tracepoint_get_internal_filter(
219 const struct lttng_event_rule *rule)
220{
221 struct lttng_event_rule_kernel_tracepoint *tracepoint;
222
223 assert(rule);
224 tracepoint = container_of(
225 rule, struct lttng_event_rule_kernel_tracepoint, parent);
226 return tracepoint->internal_filter.filter;
227}
228
229static const struct lttng_bytecode *
230lttng_event_rule_kernel_tracepoint_get_internal_filter_bytecode(
231 const struct lttng_event_rule *rule)
232{
233 struct lttng_event_rule_kernel_tracepoint *tracepoint;
234
235 assert(rule);
236 tracepoint = container_of(
237 rule, struct lttng_event_rule_kernel_tracepoint, parent);
238 return tracepoint->internal_filter.bytecode;
239}
240
241static enum lttng_event_rule_generate_exclusions_status
242lttng_event_rule_kernel_tracepoint_generate_exclusions(
243 const struct lttng_event_rule *rule,
244 struct lttng_event_exclusion **_exclusions)
245{
246 /* Unsupported. */
247 *_exclusions = NULL;
248 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
249}
250
251static unsigned long lttng_event_rule_kernel_tracepoint_hash(
252 const struct lttng_event_rule *rule)
253{
254 unsigned long hash;
255 struct lttng_event_rule_kernel_tracepoint *tp_rule =
256 container_of(rule, typeof(*tp_rule), parent);
257
258 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT,
259 lttng_ht_seed);
260 hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed);
261
262 if (tp_rule->filter_expression) {
263 hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed);
264 }
265
266 return hash;
267}
268
269struct lttng_event_rule *lttng_event_rule_kernel_tracepoint_create(void)
270{
271 struct lttng_event_rule *rule = NULL;
272 struct lttng_event_rule_kernel_tracepoint *tp_rule;
273 enum lttng_event_rule_status status;
274
275 tp_rule = zmalloc(sizeof(struct lttng_event_rule_kernel_tracepoint));
276 if (!tp_rule) {
277 goto end;
278 }
279
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;
295
296 /* Not necessary for now. */
297 tp_rule->parent.generate_lttng_event = NULL;
298
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);
303 rule = NULL;
304 }
305
306end:
307 return rule;
308}
309
310LTTNG_HIDDEN
311ssize_t lttng_event_rule_kernel_tracepoint_create_from_payload(
312 struct lttng_payload_view *view,
313 struct lttng_event_rule **_event_rule)
314{
315 ssize_t ret, offset = 0;
316 enum lttng_event_rule_status status;
317 const struct lttng_event_rule_kernel_tracepoint_comm *tracepoint_comm;
318 const char *pattern;
319 const char *filter_expression = NULL;
320 struct lttng_buffer_view current_buffer_view;
321 struct lttng_event_rule *rule = NULL;
322
323 if (!_event_rule) {
324 ret = -1;
325 goto end;
326 }
327
328 current_buffer_view = lttng_buffer_view_from_view(
329 &view->buffer, offset, sizeof(*tracepoint_comm));
330 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
331 ERR("Failed to initialize from malformed event rule kernel tracepoint: buffer too short to contain header.");
332 ret = -1;
333 goto end;
334 }
335
336 tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data;
337
338 /* Skip to payload. */
339 offset += current_buffer_view.size;
340
341 /* Map the pattern. */
342 current_buffer_view = lttng_buffer_view_from_view(
343 &view->buffer, offset, tracepoint_comm->pattern_len);
344
345 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
346 ret = -1;
347 goto end;
348 }
349
350 pattern = current_buffer_view.data;
351 if (!lttng_buffer_view_contains_string(&current_buffer_view, pattern,
352 tracepoint_comm->pattern_len)) {
353 ret = -1;
354 goto end;
355 }
356
357 /* Skip after the pattern. */
358 offset += tracepoint_comm->pattern_len;
359
360 if (!tracepoint_comm->filter_expression_len) {
361 goto skip_filter_expression;
362 }
363
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(&current_buffer_view)) {
368 ret = -1;
369 goto end;
370 }
371
372 filter_expression = current_buffer_view.data;
373 if (!lttng_buffer_view_contains_string(&current_buffer_view,
374 filter_expression,
375 tracepoint_comm->filter_expression_len)) {
376 ret = -1;
377 goto end;
378 }
379
380 /* Skip after the pattern. */
381 offset += tracepoint_comm->filter_expression_len;
382
383skip_filter_expression:
384
385 rule = lttng_event_rule_kernel_tracepoint_create();
386 if (!rule) {
387 ERR("Failed to create event rule kernel tracepoint.");
388 ret = -1;
389 goto end;
390 }
391
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.");
395 ret = -1;
396 goto end;
397 }
398
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.");
404 ret = -1;
405 goto end;
406 }
407 }
408
409 *_event_rule = rule;
410 rule = NULL;
411 ret = offset;
412end:
413 lttng_event_rule_destroy(rule);
414 return ret;
415}
416
417enum lttng_event_rule_status lttng_event_rule_kernel_tracepoint_set_name_pattern(
418 struct lttng_event_rule *rule, const char *pattern)
419{
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;
423
424 if (!rule || !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) || !pattern ||
425 strlen(pattern) == 0) {
426 status = LTTNG_EVENT_RULE_STATUS_INVALID;
427 goto end;
428 }
429
430 tracepoint = container_of(
431 rule, struct lttng_event_rule_kernel_tracepoint, parent);
432 pattern_copy = strdup(pattern);
433 if (!pattern_copy) {
434 status = LTTNG_EVENT_RULE_STATUS_ERROR;
435 goto end;
436 }
437
438 /* Normalize the pattern. */
439 strutils_normalize_star_glob_pattern(pattern_copy);
440
441 free(tracepoint->pattern);
442
443 tracepoint->pattern = pattern_copy;
444 pattern_copy = NULL;
445end:
446 return status;
447}
448
449enum lttng_event_rule_status lttng_event_rule_kernel_tracepoint_get_name_pattern(
450 const struct lttng_event_rule *rule, const char **pattern)
451{
452 struct lttng_event_rule_kernel_tracepoint *tracepoint;
453 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
454
455 if (!rule || !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) || !pattern) {
456 status = LTTNG_EVENT_RULE_STATUS_INVALID;
457 goto end;
458 }
459
460 tracepoint = container_of(
461 rule, struct lttng_event_rule_kernel_tracepoint, parent);
462 if (!tracepoint->pattern) {
463 status = LTTNG_EVENT_RULE_STATUS_UNSET;
464 goto end;
465 }
466
467 *pattern = tracepoint->pattern;
468end:
469 return status;
470}
471
472enum lttng_event_rule_status lttng_event_rule_kernel_tracepoint_set_filter(
473 struct lttng_event_rule *rule, const char *expression)
474{
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;
478
479 if (!rule || !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) || !expression ||
480 strlen(expression) == 0) {
481 status = LTTNG_EVENT_RULE_STATUS_INVALID;
482 goto end;
483 }
484
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;
491 goto end;
492 }
493
494 if (tracepoint->filter_expression) {
495 free(tracepoint->filter_expression);
496 }
497
498 tracepoint->filter_expression = expression_copy;
499 expression_copy = NULL;
500end:
501 return status;
502}
503
504enum lttng_event_rule_status lttng_event_rule_kernel_tracepoint_get_filter(
505 const struct lttng_event_rule *rule, const char **expression)
506{
507 struct lttng_event_rule_kernel_tracepoint *tracepoint;
508 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
509
510 if (!rule || !IS_KERNEL_TRACEPOINT_EVENT_RULE(rule) || !expression) {
511 status = LTTNG_EVENT_RULE_STATUS_INVALID;
512 goto end;
513 }
514
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;
519 goto end;
520 }
521
522 *expression = tracepoint->filter_expression;
523end:
524 return status;
525}
This page took 0.040627 seconds and 4 git commands to generate.