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