event-rule: introduce event-rule kprobe
[lttng-tools.git] / src / common / kernel-probe.c
CommitLineData
808cb744
JR
1/*
2 * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include "lttng/lttng-error.h"
9#include <assert.h>
10#include <common/error.h>
11#include <common/macros.h>
12#include <common/payload.h>
13#include <common/payload-view.h>
14#include <fcntl.h>
15#include <lttng/constant.h>
16#include <lttng/kernel-probe.h>
17#include <lttng/kernel-probe-internal.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <sys/unistd.h>
21
22static
23int lttng_kernel_probe_location_address_serialize(
24 const struct lttng_kernel_probe_location *location,
25 struct lttng_payload *payload);
26
27static
28int lttng_kernel_probe_location_symbol_serialize(
29 const struct lttng_kernel_probe_location *location,
30 struct lttng_payload *payload);
31
32static
33bool lttng_kernel_probe_location_address_is_equal(
34 const struct lttng_kernel_probe_location *a,
35 const struct lttng_kernel_probe_location *b);
36
37static
38bool lttng_kernel_probe_location_symbol_is_equal(
39 const struct lttng_kernel_probe_location *a,
40 const struct lttng_kernel_probe_location *b);
41
42enum lttng_kernel_probe_location_type lttng_kernel_probe_location_get_type(
43 const struct lttng_kernel_probe_location *location)
44{
45 return location ? location->type :
46 LTTNG_KERNEL_PROBE_LOCATION_TYPE_UNKNOWN;
47}
48
49static
50void lttng_kernel_probe_location_address_destroy(
51 struct lttng_kernel_probe_location *location)
52{
53 assert(location);
54 free(location);
55}
56
57static
58void lttng_kernel_probe_location_symbol_destroy(
59 struct lttng_kernel_probe_location *location)
60{
61 struct lttng_kernel_probe_location_symbol *location_symbol = NULL;
62
63 assert(location);
64
65 location_symbol = container_of(location,
66 struct lttng_kernel_probe_location_symbol,
67 parent);
68
69 assert(location_symbol);
70
71 free(location_symbol->symbol_name);
72 free(location);
73}
74
75void lttng_kernel_probe_location_destroy(
76 struct lttng_kernel_probe_location *location)
77{
78 if (!location) {
79 return;
80 }
81
82 switch (location->type) {
83 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
84 lttng_kernel_probe_location_address_destroy(location);
85 break;
86 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
87 lttng_kernel_probe_location_symbol_destroy(location);
88 break;
89 default:
90 abort();
91 }
92}
93
94struct lttng_kernel_probe_location *
95lttng_kernel_probe_location_address_create(uint64_t address)
96{
97 struct lttng_kernel_probe_location *ret = NULL;
98 struct lttng_kernel_probe_location_address *location;
99
100 location = zmalloc(sizeof(*location));
101 if (!location) {
077192fd 102 PERROR("Error allocating userspace probe location.");
808cb744
JR
103 goto end;
104 }
105
106 location->address = address;
107
108 ret = &location->parent;
109 ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS;
110 ret->equal = lttng_kernel_probe_location_address_is_equal;
111 ret->serialize = lttng_kernel_probe_location_address_serialize;
112
113end:
114 return ret;
115}
116
117struct lttng_kernel_probe_location *
118lttng_kernel_probe_location_symbol_create(const char *symbol_name,
119 uint64_t offset)
120{
121 char *symbol_name_copy = NULL;
122 struct lttng_kernel_probe_location *ret = NULL;
123 struct lttng_kernel_probe_location_symbol *location;
124
125 if (!symbol_name || strlen(symbol_name) >= LTTNG_SYMBOL_NAME_LEN) {
126 goto error;
127 }
128
129 symbol_name_copy = strdup(symbol_name);
130 if (!symbol_name_copy) {
131 PERROR("Failed to copy symbol name '%s'", symbol_name);
132 goto error;
133 }
134
135 location = zmalloc(sizeof(*location));
136 if (!location) {
137 PERROR("Failed to allocate kernel symbol probe location");
138 goto error;
139 }
140
141 location->symbol_name = symbol_name_copy;
142 location->offset = offset;
143
144 ret = &location->parent;
145 ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET;
146 ret->equal = lttng_kernel_probe_location_symbol_is_equal;
147 ret->serialize = lttng_kernel_probe_location_symbol_serialize;
148 goto end;
149
150error:
151 free(symbol_name_copy);
152end:
153 return ret;
154}
155
156enum lttng_kernel_probe_location_status
157lttng_kernel_probe_location_address_get_address(
158 const struct lttng_kernel_probe_location *location,
159 uint64_t *offset)
160{
161 enum lttng_kernel_probe_location_status ret =
162 LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK;
163 struct lttng_kernel_probe_location_address *address_location;
164
165 assert(offset);
166
167 if (!location || lttng_kernel_probe_location_get_type(location) !=
168 LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS) {
169 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
170 ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID;
171 goto end;
172 }
173
174 address_location = container_of(location,
175 struct lttng_kernel_probe_location_address, parent);
176 *offset = address_location->address;
177end:
178 return ret;
179}
180
181const char *lttng_kernel_probe_location_symbol_get_name(
182 const struct lttng_kernel_probe_location *location)
183{
184 const char *ret = NULL;
185 struct lttng_kernel_probe_location_symbol *symbol_location;
186
187 if (!location || lttng_kernel_probe_location_get_type(location) !=
188 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) {
189 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
190 goto end;
191 }
192
193 symbol_location = container_of(location,
194 struct lttng_kernel_probe_location_symbol, parent);
195 ret = symbol_location->symbol_name;
196end:
197 return ret;
198}
199
200enum lttng_kernel_probe_location_status
201lttng_kernel_probe_location_symbol_get_offset(
202 const struct lttng_kernel_probe_location *location,
203 uint64_t *offset)
204{
205 enum lttng_kernel_probe_location_status ret =
206 LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK;
207 struct lttng_kernel_probe_location_symbol *symbol_location;
208
209 assert(offset);
210
211 if (!location || lttng_kernel_probe_location_get_type(location) !=
212 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) {
213 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
214 ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID;
215 goto end;
216 }
217
218 symbol_location = container_of(location,
219 struct lttng_kernel_probe_location_symbol, parent);
220 *offset = symbol_location->offset;
221end:
222 return ret;
223}
224
225static
226int lttng_kernel_probe_location_symbol_serialize(
227 const struct lttng_kernel_probe_location *location,
228 struct lttng_payload *payload)
229{
230 int ret;
231 size_t symbol_name_len;
232 size_t original_payload_size;
233 struct lttng_kernel_probe_location_symbol *location_symbol;
234 struct lttng_kernel_probe_location_symbol_comm location_symbol_comm;
235
236 if (!location || !payload) {
237 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
238 ret = -LTTNG_ERR_INVALID;
239 goto end;
240 }
241
242 assert(lttng_kernel_probe_location_get_type(location) ==
243 LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
244
245 original_payload_size = payload->buffer.size;
246 location_symbol = container_of(location,
247 struct lttng_kernel_probe_location_symbol, parent);
248
249 if (!location_symbol->symbol_name) {
250 ret = -LTTNG_ERR_INVALID;
251 goto end;
252 }
253
254 symbol_name_len = strlen(location_symbol->symbol_name);
255 if (symbol_name_len == 0) {
256 ret = -LTTNG_ERR_INVALID;
257 goto end;
258 }
259
260 location_symbol_comm.symbol_len = symbol_name_len + 1;
261 location_symbol_comm.offset = location_symbol->offset;
262
263 ret = lttng_dynamic_buffer_append(&payload->buffer,
264 &location_symbol_comm, sizeof(location_symbol_comm));
265 if (ret) {
266 ret = -LTTNG_ERR_INVALID;
267 goto end;
268 }
269
270 ret = lttng_dynamic_buffer_append(&payload->buffer,
271 location_symbol->symbol_name,
272 location_symbol_comm.symbol_len);
273 if (ret) {
274 ret = -LTTNG_ERR_INVALID;
275 goto end;
276 }
277
278 ret = (int) (payload->buffer.size - original_payload_size);
279end:
280 return ret;
281}
282
283static
284int lttng_kernel_probe_location_address_serialize(
285 const struct lttng_kernel_probe_location *location,
286 struct lttng_payload *payload)
287{
288 int ret;
289 size_t original_payload_size;
290 struct lttng_kernel_probe_location_address *location_address;
291 struct lttng_kernel_probe_location_address_comm location_address_comm;
292
293 assert(location);
294 assert(lttng_kernel_probe_location_get_type(location) ==
295 LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
296
297 original_payload_size = payload->buffer.size;
298 location_address = container_of(location,
299 struct lttng_kernel_probe_location_address,
300 parent);
301
302 location_address_comm.address = location_address->address;
303
304 ret = lttng_dynamic_buffer_append(&payload->buffer,
305 &location_address_comm,
306 sizeof(location_address_comm));
307 if (ret) {
308 ret = -LTTNG_ERR_INVALID;
309 goto end;
310 }
311
312 ret = (int) (payload->buffer.size - original_payload_size);
313end:
314 return ret;
315}
316
317LTTNG_HIDDEN
318int lttng_kernel_probe_location_serialize(
319 const struct lttng_kernel_probe_location *location,
320 struct lttng_payload *payload)
321{
322 int ret;
323 size_t original_payload_size;
324 struct lttng_kernel_probe_location_comm location_generic_comm = {};
325
326 if (!location || !payload) {
327 ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
328 ret = -LTTNG_ERR_INVALID;
329 goto end;
330 }
331
332 original_payload_size = payload->buffer.size;
333 location_generic_comm.type = (int8_t) location->type;
334 ret = lttng_dynamic_buffer_append(&payload->buffer,
335 &location_generic_comm,
336 sizeof(location_generic_comm));
337 if (ret) {
338 goto end;
339 }
340
341 ret = location->serialize(location, payload);
342 if (ret < 0) {
343 goto end;
344 }
345
346 ret = (int) (payload->buffer.size - original_payload_size);
347end:
348 return ret;
349}
350
351static
352int lttng_kernel_probe_location_symbol_create_from_payload(
353 struct lttng_payload_view *view,
354 struct lttng_kernel_probe_location **location)
355{
356 struct lttng_kernel_probe_location_symbol_comm *location_symbol_comm;
357 const char *symbol_name_src;
358 ssize_t ret = 0;
359 size_t expected_size;
360
361 assert(location);
362
363 if (view->buffer.size < sizeof(*location_symbol_comm)) {
364 ret = -LTTNG_ERR_INVALID;
365 goto end;
366 }
367
368 location_symbol_comm =
369 (typeof(location_symbol_comm)) view->buffer.data;
370
371 expected_size = sizeof(*location_symbol_comm) +
372 location_symbol_comm->symbol_len;
373
374 if (view->buffer.size < expected_size) {
375 ret = -LTTNG_ERR_INVALID;
376 goto end;
377 }
378
379 symbol_name_src = view->buffer.data + sizeof(*location_symbol_comm);
380
381 if (!lttng_buffer_view_contains_string(&view->buffer, symbol_name_src,
382 location_symbol_comm->symbol_len)) {
383 ret = -LTTNG_ERR_INVALID;
384 goto end;
385 }
386
387 *location = lttng_kernel_probe_location_symbol_create(
388 symbol_name_src, location_symbol_comm->offset);
389 if (!(*location)) {
390 ret = -LTTNG_ERR_INVALID;
391 goto end;
392 }
393
394 ret = (ssize_t) expected_size;
395end:
396 return ret;
397}
398
399static
400ssize_t lttng_kernel_probe_location_address_create_from_payload(
401 struct lttng_payload_view *view,
402 struct lttng_kernel_probe_location **location)
403{
404 struct lttng_kernel_probe_location_address_comm *location_address_comm;
405 ssize_t ret = 0;
406 size_t expected_size;
407
408 assert(location);
409
410 expected_size = sizeof(*location_address_comm);
411
412 if (view->buffer.size < expected_size) {
413 ret = -LTTNG_ERR_INVALID;
414 goto end;
415 }
416
417 location_address_comm =
418 (typeof(location_address_comm)) view->buffer.data;
419
420 *location = lttng_kernel_probe_location_address_create(location_address_comm->address);
421 if (!(*location)) {
422 ret = -LTTNG_ERR_INVALID;
423 goto end;
424 }
425
426 ret = (size_t) expected_size;
427end:
428 return ret;
429}
430
431LTTNG_HIDDEN
432ssize_t lttng_kernel_probe_location_create_from_payload(
433 struct lttng_payload_view *view,
434 struct lttng_kernel_probe_location **location)
435{
436 struct lttng_kernel_probe_location_comm *probe_location_comm;
437 enum lttng_kernel_probe_location_type type;
438 ssize_t consumed = 0;
439 ssize_t ret;
440
441 assert(view);
442 assert(location);
443
444 if (view->buffer.size <= sizeof(*probe_location_comm)) {
445 ret = -LTTNG_ERR_INVALID;
446 goto end;
447 }
448
449 probe_location_comm = (typeof(probe_location_comm)) view->buffer.data;
450 type = (enum lttng_kernel_probe_location_type) probe_location_comm->type;
451 consumed += sizeof(*probe_location_comm);
452
453 switch (type) {
454 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
455 {
456 struct lttng_payload_view location_view =
457 lttng_payload_view_from_view(
458 view, consumed, -1);
459
460 ret = lttng_kernel_probe_location_symbol_create_from_payload(
461 &location_view, location);
462 break;
463 }
464 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
465 {
466 struct lttng_payload_view location_view =
467 lttng_payload_view_from_view(view, consumed, -1);
468
469 ret = lttng_kernel_probe_location_address_create_from_payload(
470 &location_view, location);
471 break;
472 }
473 default:
474 ret = -LTTNG_ERR_INVALID;
475 break;
476 }
477
478 if (ret < 0) {
479 ret = -LTTNG_ERR_INVALID;
480 goto end;
481 }
482
483 ret += consumed;
484
485end:
486 return ret;
487}
488
489static
490bool lttng_kernel_probe_location_address_is_equal(
491 const struct lttng_kernel_probe_location *_a,
492 const struct lttng_kernel_probe_location *_b)
493{
494 bool is_equal = false;
495 struct lttng_kernel_probe_location_address *a, *b;
496
497 a = container_of(_a, struct lttng_kernel_probe_location_address,
498 parent);
499 b = container_of(_b, struct lttng_kernel_probe_location_address,
500 parent);
501
502 if (a->address != b->address) {
503 goto end;
504 }
505
506 is_equal = true;
507
508end:
509 return is_equal;
510}
511
512static
513bool lttng_kernel_probe_location_symbol_is_equal(
514 const struct lttng_kernel_probe_location *_a,
515 const struct lttng_kernel_probe_location *_b)
516{
517 bool is_equal = false;
518 struct lttng_kernel_probe_location_symbol *a, *b;
519
520 a = container_of(_a, struct lttng_kernel_probe_location_symbol,
521 parent);
522 b = container_of(_b, struct lttng_kernel_probe_location_symbol,
523 parent);
524
525 assert(a->symbol_name);
526 assert(b->symbol_name);
527 if (strcmp(a->symbol_name, b->symbol_name)) {
528 goto end;
529 }
530
531 if (a->offset != b->offset) {
532 goto end;
533 }
534
535 is_equal = true;
536
537end:
538 return is_equal;
539}
540
541LTTNG_HIDDEN
542bool lttng_kernel_probe_location_is_equal(
543 const struct lttng_kernel_probe_location *a,
544 const struct lttng_kernel_probe_location *b)
545{
546 bool is_equal = false;
547
548 if (!a || !b) {
549 goto end;
550 }
551
552 if (a == b) {
553 is_equal = true;
554 goto end;
555 }
556
557 if (a->type != b->type) {
558 goto end;
559 }
560
561 is_equal = a->equal ? a->equal(a, b) : true;
562end:
563 return is_equal;
564}
077192fd
JR
565
566static struct lttng_kernel_probe_location *
567lttng_kernel_probe_location_symbol_copy(
568 const struct lttng_kernel_probe_location *location)
569{
570 struct lttng_kernel_probe_location *new_location = NULL;
571 struct lttng_kernel_probe_location_symbol *symbol_location;
572 enum lttng_kernel_probe_location_status status;
573 const char *symbol_name = NULL;
574 uint64_t offset;
575
576 assert(location);
577 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
578 symbol_location = container_of(
579 location, typeof(*symbol_location), parent);
580
581 /* Get probe location offset */
582 status = lttng_kernel_probe_location_symbol_get_offset(location, &offset);
583 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
584 ERR("Get kernel probe location offset failed.");
585 goto error;
586 }
587
588 symbol_name = lttng_kernel_probe_location_symbol_get_name(location);
589 if (!symbol_name) {
590 ERR("Kernel probe symbol name is NULL.");
591 goto error;
592 }
593
594 /* Create the probe_location */
595 new_location = lttng_kernel_probe_location_symbol_create(
596 symbol_name, offset);
597
598 goto end;
599
600error:
601 new_location = NULL;
602end:
603 return new_location;
604}
605static struct lttng_kernel_probe_location *
606lttng_kernel_probe_location_address_copy(
607 const struct lttng_kernel_probe_location *location)
608{
609 struct lttng_kernel_probe_location *new_location = NULL;
610 struct lttng_kernel_probe_location_address *address_location;
611 enum lttng_kernel_probe_location_status status;
612 uint64_t address;
613
614 assert(location);
615 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
616 address_location = container_of(
617 location, typeof(*address_location), parent);
618
619
620 /* Get probe location fields */
621 status = lttng_kernel_probe_location_address_get_address(location, &address);
622 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
623 ERR("Get kernel probe address failed.");
624 goto error;
625 }
626
627 /* Create the probe_location */
628 new_location = lttng_kernel_probe_location_address_create(address);
629
630 goto end;
631
632error:
633 new_location = NULL;
634end:
635 return new_location;
636}
637
638LTTNG_HIDDEN
639struct lttng_kernel_probe_location *lttng_kernel_probe_location_copy(
640 const struct lttng_kernel_probe_location *location)
641{
642 struct lttng_kernel_probe_location *new_location = NULL;
643 enum lttng_kernel_probe_location_type type;
644
645 if (!location) {
646 goto err;
647 }
648
649 type = lttng_kernel_probe_location_get_type(location);
650 switch (type) {
651 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
652 new_location =
653 lttng_kernel_probe_location_address_copy(location);
654 if (!new_location) {
655 goto err;
656 }
657 break;
658 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
659 new_location =
660 lttng_kernel_probe_location_symbol_copy(location);
661 if (!new_location) {
662 goto err;
663 }
664 break;
665 default:
666 new_location = NULL;
667 goto err;
668 }
669err:
670 return new_location;
671}
This page took 0.072825 seconds and 4 git commands to generate.