Run clang-format on the whole tree
[lttng-tools.git] / src / common / event-rule / kernel-uprobe.cpp
... / ...
CommitLineData
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 <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/payload-view.hpp>
15#include <common/payload.hpp>
16#include <common/runas.hpp>
17
18#include <lttng/event-rule/event-rule-internal.hpp>
19#include <lttng/event-rule/kernel-uprobe-internal.hpp>
20#include <lttng/userspace-probe-internal.hpp>
21
22#define IS_UPROBE_EVENT_RULE(rule) \
23 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE)
24
25static void lttng_event_rule_kernel_uprobe_destroy(struct lttng_event_rule *rule)
26{
27 struct lttng_event_rule_kernel_uprobe *uprobe;
28
29 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
30
31 lttng_userspace_probe_location_destroy(uprobe->location);
32 free(uprobe->name);
33 free(uprobe);
34}
35
36static bool lttng_event_rule_kernel_uprobe_validate(const struct lttng_event_rule *rule)
37{
38 bool valid = false;
39 struct lttng_event_rule_kernel_uprobe *uprobe;
40
41 if (!rule) {
42 goto end;
43 }
44
45 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
46
47 /* Required field. */
48 if (!uprobe->name) {
49 ERR("Invalid uprobe event rule: a pattern must be set.");
50 goto end;
51 }
52
53 if (!uprobe->location) {
54 ERR("Invalid uprobe event rule: a location must be set.");
55 goto end;
56 }
57
58 valid = true;
59end:
60 return valid;
61}
62
63static int lttng_event_rule_kernel_uprobe_serialize(const struct lttng_event_rule *rule,
64 struct lttng_payload *payload)
65{
66 int ret;
67 size_t name_len, header_offset, size_before_probe;
68 struct lttng_event_rule_kernel_uprobe *uprobe;
69 struct lttng_event_rule_kernel_uprobe_comm uprobe_comm = {};
70 struct lttng_event_rule_kernel_uprobe_comm *header;
71
72 if (!rule || !IS_UPROBE_EVENT_RULE(rule)) {
73 ret = -1;
74 goto end;
75 }
76
77 header_offset = payload->buffer.size;
78
79 DBG("Serializing uprobe event rule.");
80 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
81
82 name_len = strlen(uprobe->name) + 1;
83
84 uprobe_comm.name_len = name_len;
85
86 ret = lttng_dynamic_buffer_append(&payload->buffer, &uprobe_comm, sizeof(uprobe_comm));
87 if (ret) {
88 goto end;
89 }
90 ret = lttng_dynamic_buffer_append(&payload->buffer, uprobe->name, name_len);
91 if (ret) {
92 goto end;
93 }
94
95 size_before_probe = payload->buffer.size;
96
97 /* This serialize return the size taken in the buffer. */
98 ret = lttng_userspace_probe_location_serialize(uprobe->location, payload);
99 if (ret < 0) {
100 goto end;
101 }
102
103 /* Update the header regarding the probe size. */
104 header = (struct lttng_event_rule_kernel_uprobe_comm *) ((char *) payload->buffer.data +
105 header_offset);
106 header->location_len = payload->buffer.size - size_before_probe;
107
108 ret = 0;
109
110end:
111 return ret;
112}
113
114static bool lttng_event_rule_kernel_uprobe_is_equal(const struct lttng_event_rule *_a,
115 const struct lttng_event_rule *_b)
116{
117 bool is_equal = false;
118 struct lttng_event_rule_kernel_uprobe *a, *b;
119
120 a = lttng::utils::container_of(_a, &lttng_event_rule_kernel_uprobe::parent);
121 b = lttng::utils::container_of(_b, &lttng_event_rule_kernel_uprobe::parent);
122
123 /* uprobe is invalid if this is not true. */
124 LTTNG_ASSERT(a->name);
125 LTTNG_ASSERT(b->name);
126 if (strcmp(a->name, b->name)) {
127 goto end;
128 }
129
130 LTTNG_ASSERT(a->location);
131 LTTNG_ASSERT(b->location);
132 is_equal = lttng_userspace_probe_location_is_equal(a->location, b->location);
133end:
134 return is_equal;
135}
136
137static enum lttng_error_code lttng_event_rule_kernel_uprobe_generate_filter_bytecode(
138 struct lttng_event_rule *rule __attribute__((unused)),
139 const struct lttng_credentials *creds __attribute__((unused)))
140{
141 /* Nothing to do. */
142 return LTTNG_OK;
143}
144
145static const char *lttng_event_rule_kernel_uprobe_get_filter(const struct lttng_event_rule *rule
146 __attribute__((unused)))
147{
148 /* Unsupported. */
149 return NULL;
150}
151
152static const struct lttng_bytecode *
153lttng_event_rule_kernel_uprobe_get_filter_bytecode(const struct lttng_event_rule *rule
154 __attribute__((unused)))
155{
156 /* Unsupported. */
157 return NULL;
158}
159
160static enum lttng_event_rule_generate_exclusions_status
161lttng_event_rule_kernel_uprobe_generate_exclusions(const struct lttng_event_rule *rule
162 __attribute__((unused)),
163 struct lttng_event_exclusion **exclusions)
164{
165 /* Unsupported. */
166 *exclusions = NULL;
167 return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
168}
169
170static unsigned long lttng_event_rule_kernel_uprobe_hash(const struct lttng_event_rule *rule)
171{
172 unsigned long hash;
173 struct lttng_event_rule_kernel_uprobe *urule =
174 lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
175
176 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE, lttng_ht_seed);
177 hash ^= hash_key_str(urule->name, lttng_ht_seed);
178 hash ^= lttng_userspace_probe_location_hash(urule->location);
179
180 return hash;
181}
182
183static int userspace_probe_set_location(struct lttng_event_rule_kernel_uprobe *uprobe,
184 const struct lttng_userspace_probe_location *location)
185{
186 int ret;
187 struct lttng_userspace_probe_location *location_copy = NULL;
188
189 if (!uprobe || !location || uprobe->location) {
190 ret = -1;
191 goto end;
192 }
193
194 location_copy = lttng_userspace_probe_location_copy(location);
195 if (!location_copy) {
196 ret = -1;
197 goto end;
198 }
199
200 uprobe->location = location_copy;
201 location_copy = NULL;
202 ret = 0;
203end:
204 lttng_userspace_probe_location_destroy(location_copy);
205 return ret;
206}
207
208static enum lttng_error_code
209lttng_event_rule_kernel_uprobe_mi_serialize(const struct lttng_event_rule *rule,
210 struct mi_writer *writer)
211{
212 int ret;
213 enum lttng_error_code ret_code;
214 enum lttng_event_rule_status status;
215 const char *event_name = NULL;
216 const struct lttng_userspace_probe_location *location = NULL;
217
218 LTTNG_ASSERT(rule);
219 LTTNG_ASSERT(writer);
220 LTTNG_ASSERT(IS_UPROBE_EVENT_RULE(rule));
221
222 status = lttng_event_rule_kernel_uprobe_get_event_name(rule, &event_name);
223 LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
224 LTTNG_ASSERT(event_name);
225
226 status = lttng_event_rule_kernel_uprobe_get_location(rule, &location);
227 LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
228 LTTNG_ASSERT(location);
229
230 /* Open event rule kernel uprobe element. */
231 ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_rule_kernel_uprobe);
232 if (ret) {
233 goto mi_error;
234 }
235
236 /* Event name. */
237 ret = mi_lttng_writer_write_element_string(
238 writer, mi_lttng_element_event_rule_event_name, event_name);
239 if (ret) {
240 goto mi_error;
241 }
242
243 /* Probe location. */
244 ret_code = lttng_userspace_probe_location_mi_serialize(location, writer);
245 if (ret_code != LTTNG_OK) {
246 goto end;
247 }
248
249 /* Close event rule kernel uprobe element. */
250 ret = mi_lttng_writer_close_element(writer);
251 if (ret) {
252 goto mi_error;
253 }
254
255 ret_code = LTTNG_OK;
256 goto end;
257
258mi_error:
259 ret_code = LTTNG_ERR_MI_IO_FAIL;
260end:
261 return ret_code;
262}
263
264struct lttng_event_rule *
265lttng_event_rule_kernel_uprobe_create(const struct lttng_userspace_probe_location *location)
266{
267 struct lttng_event_rule *rule = NULL;
268 struct lttng_event_rule_kernel_uprobe *urule;
269
270 urule = zmalloc<lttng_event_rule_kernel_uprobe>();
271 if (!urule) {
272 goto end;
273 }
274
275 rule = &urule->parent;
276 lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
277 urule->parent.validate = lttng_event_rule_kernel_uprobe_validate;
278 urule->parent.serialize = lttng_event_rule_kernel_uprobe_serialize;
279 urule->parent.equal = lttng_event_rule_kernel_uprobe_is_equal;
280 urule->parent.destroy = lttng_event_rule_kernel_uprobe_destroy;
281 urule->parent.generate_filter_bytecode =
282 lttng_event_rule_kernel_uprobe_generate_filter_bytecode;
283 urule->parent.get_filter = lttng_event_rule_kernel_uprobe_get_filter;
284 urule->parent.get_filter_bytecode = lttng_event_rule_kernel_uprobe_get_filter_bytecode;
285 urule->parent.generate_exclusions = lttng_event_rule_kernel_uprobe_generate_exclusions;
286 urule->parent.hash = lttng_event_rule_kernel_uprobe_hash;
287 urule->parent.mi_serialize = lttng_event_rule_kernel_uprobe_mi_serialize;
288
289 if (userspace_probe_set_location(urule, location)) {
290 lttng_event_rule_destroy(rule);
291 rule = NULL;
292 }
293
294end:
295 return rule;
296}
297
298ssize_t lttng_event_rule_kernel_uprobe_create_from_payload(struct lttng_payload_view *view,
299 struct lttng_event_rule **_event_rule)
300{
301 ssize_t ret, offset = 0;
302 const struct lttng_event_rule_kernel_uprobe_comm *uprobe_comm;
303 const char *name;
304 struct lttng_buffer_view current_buffer_view;
305 struct lttng_event_rule *rule = NULL;
306 struct lttng_userspace_probe_location *location = NULL;
307 enum lttng_event_rule_status status;
308
309 if (!_event_rule) {
310 ret = -1;
311 goto end;
312 }
313
314 current_buffer_view =
315 lttng_buffer_view_from_view(&view->buffer, offset, sizeof(*uprobe_comm));
316 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
317 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
318 ret = -1;
319 goto end;
320 }
321
322 uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
323
324 /* Skip to payload. */
325 offset += current_buffer_view.size;
326
327 /* Map the name. */
328 current_buffer_view =
329 lttng_buffer_view_from_view(&view->buffer, offset, uprobe_comm->name_len);
330 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
331 ret = -1;
332 goto end;
333 }
334
335 name = current_buffer_view.data;
336 if (!lttng_buffer_view_contains_string(&current_buffer_view, name, uprobe_comm->name_len)) {
337 ret = -1;
338 goto end;
339 }
340
341 /* Skip after the name. */
342 offset += uprobe_comm->name_len;
343
344 /* Map the location. */
345 {
346 struct lttng_payload_view current_payload_view =
347 lttng_payload_view_from_view(view, offset, uprobe_comm->location_len);
348
349 if (!lttng_payload_view_is_valid(&current_payload_view)) {
350 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
351 ret = -1;
352 goto end;
353 }
354
355 ret = lttng_userspace_probe_location_create_from_payload(&current_payload_view,
356 &location);
357 if (ret < 0) {
358 ret = -1;
359 goto end;
360 }
361 }
362
363 LTTNG_ASSERT(ret == uprobe_comm->location_len);
364
365 /* Skip after the location. */
366 offset += uprobe_comm->location_len;
367
368 rule = lttng_event_rule_kernel_uprobe_create(location);
369 if (!rule) {
370 ERR("Failed to create event rule uprobe.");
371 ret = -1;
372 goto end;
373 }
374
375 status = lttng_event_rule_kernel_uprobe_set_event_name(rule, name);
376 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
377 ret = -1;
378 goto end;
379 }
380
381 if (!lttng_event_rule_kernel_uprobe_validate(rule)) {
382 ret = -1;
383 goto end;
384 }
385
386 *_event_rule = rule;
387 rule = NULL;
388 ret = offset;
389end:
390 lttng_userspace_probe_location_destroy(location);
391 lttng_event_rule_destroy(rule);
392 return ret;
393}
394
395enum lttng_event_rule_status
396lttng_event_rule_kernel_uprobe_get_location(const struct lttng_event_rule *rule,
397 const struct lttng_userspace_probe_location **location)
398{
399 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
400
401 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
402 status = LTTNG_EVENT_RULE_STATUS_INVALID;
403 goto end;
404 }
405
406 *location = lttng_event_rule_kernel_uprobe_get_location_mutable(rule);
407 if (!*location) {
408 status = LTTNG_EVENT_RULE_STATUS_UNSET;
409 goto end;
410 }
411
412end:
413 return status;
414}
415
416struct lttng_userspace_probe_location *
417lttng_event_rule_kernel_uprobe_get_location_mutable(const struct lttng_event_rule *rule)
418{
419 struct lttng_event_rule_kernel_uprobe *uprobe;
420
421 LTTNG_ASSERT(rule);
422 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
423
424 return uprobe->location;
425}
426
427enum lttng_event_rule_status
428lttng_event_rule_kernel_uprobe_set_event_name(struct lttng_event_rule *rule, const char *name)
429{
430 char *name_copy = NULL;
431 struct lttng_event_rule_kernel_uprobe *uprobe;
432 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
433
434 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name || strlen(name) == 0) {
435 status = LTTNG_EVENT_RULE_STATUS_INVALID;
436 goto end;
437 }
438
439 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
440 name_copy = strdup(name);
441 if (!name_copy) {
442 status = LTTNG_EVENT_RULE_STATUS_ERROR;
443 goto end;
444 }
445
446 if (uprobe->name) {
447 free(uprobe->name);
448 }
449
450 uprobe->name = name_copy;
451 name_copy = NULL;
452end:
453 return status;
454}
455
456enum lttng_event_rule_status
457lttng_event_rule_kernel_uprobe_get_event_name(const struct lttng_event_rule *rule,
458 const char **name)
459{
460 struct lttng_event_rule_kernel_uprobe *uprobe;
461 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
462
463 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
464 status = LTTNG_EVENT_RULE_STATUS_INVALID;
465 goto end;
466 }
467
468 uprobe = lttng::utils::container_of(rule, &lttng_event_rule_kernel_uprobe::parent);
469 if (!uprobe->name) {
470 status = LTTNG_EVENT_RULE_STATUS_UNSET;
471 goto end;
472 }
473
474 *name = uprobe->name;
475end:
476 return status;
477}
This page took 0.024123 seconds and 4 git commands to generate.