27ca02c99d09ea03212bd7d1489221d17270f50c
[lttng-tools.git] / src / common / kernel-probe.c
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
22 static
23 int lttng_kernel_probe_location_address_serialize(
24 const struct lttng_kernel_probe_location *location,
25 struct lttng_payload *payload);
26
27 static
28 int lttng_kernel_probe_location_symbol_serialize(
29 const struct lttng_kernel_probe_location *location,
30 struct lttng_payload *payload);
31
32 static
33 bool lttng_kernel_probe_location_address_is_equal(
34 const struct lttng_kernel_probe_location *a,
35 const struct lttng_kernel_probe_location *b);
36
37 static
38 bool lttng_kernel_probe_location_symbol_is_equal(
39 const struct lttng_kernel_probe_location *a,
40 const struct lttng_kernel_probe_location *b);
41
42 enum 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
49 static
50 void lttng_kernel_probe_location_address_destroy(
51 struct lttng_kernel_probe_location *location)
52 {
53 assert(location);
54 free(location);
55 }
56
57 static
58 void 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
75 void 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
94 struct lttng_kernel_probe_location *
95 lttng_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) {
102 PERROR("Error allocating userspace probe location.");
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
113 end:
114 return ret;
115 }
116
117 struct lttng_kernel_probe_location *
118 lttng_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
150 error:
151 free(symbol_name_copy);
152 end:
153 return ret;
154 }
155
156 enum lttng_kernel_probe_location_status
157 lttng_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;
177 end:
178 return ret;
179 }
180
181 const 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;
196 end:
197 return ret;
198 }
199
200 enum lttng_kernel_probe_location_status
201 lttng_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;
221 end:
222 return ret;
223 }
224
225 static
226 int 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);
279 end:
280 return ret;
281 }
282
283 static
284 int 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);
313 end:
314 return ret;
315 }
316
317 LTTNG_HIDDEN
318 int 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);
347 end:
348 return ret;
349 }
350
351 static
352 int 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;
395 end:
396 return ret;
397 }
398
399 static
400 ssize_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;
427 end:
428 return ret;
429 }
430
431 LTTNG_HIDDEN
432 ssize_t lttng_kernel_probe_location_create_from_payload(
433 struct lttng_payload_view *view,
434 struct lttng_kernel_probe_location **location)
435 {
436 enum lttng_kernel_probe_location_type type;
437 ssize_t consumed = 0;
438 ssize_t ret;
439 const struct lttng_kernel_probe_location_comm *probe_location_comm;
440 const struct lttng_payload_view probe_location_comm_view =
441 lttng_payload_view_from_view(
442 view, 0, sizeof(*probe_location_comm));
443
444 assert(view);
445 assert(location);
446
447 if (!lttng_payload_view_is_valid(&probe_location_comm_view)) {
448 ret = -LTTNG_ERR_INVALID;
449 goto end;
450 }
451
452 probe_location_comm = (typeof(probe_location_comm)) probe_location_comm_view.buffer.data;
453 type = (enum lttng_kernel_probe_location_type) probe_location_comm->type;
454 consumed += sizeof(*probe_location_comm);
455
456 switch (type) {
457 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
458 {
459 struct lttng_payload_view location_view =
460 lttng_payload_view_from_view(
461 view, consumed, -1);
462
463 ret = lttng_kernel_probe_location_symbol_create_from_payload(
464 &location_view, location);
465 break;
466 }
467 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
468 {
469 struct lttng_payload_view location_view =
470 lttng_payload_view_from_view(view, consumed, -1);
471
472 ret = lttng_kernel_probe_location_address_create_from_payload(
473 &location_view, location);
474 break;
475 }
476 default:
477 ret = -LTTNG_ERR_INVALID;
478 break;
479 }
480
481 if (ret < 0) {
482 ret = -LTTNG_ERR_INVALID;
483 goto end;
484 }
485
486 ret += consumed;
487
488 end:
489 return ret;
490 }
491
492 static
493 bool lttng_kernel_probe_location_address_is_equal(
494 const struct lttng_kernel_probe_location *_a,
495 const struct lttng_kernel_probe_location *_b)
496 {
497 bool is_equal = false;
498 struct lttng_kernel_probe_location_address *a, *b;
499
500 a = container_of(_a, struct lttng_kernel_probe_location_address,
501 parent);
502 b = container_of(_b, struct lttng_kernel_probe_location_address,
503 parent);
504
505 if (a->address != b->address) {
506 goto end;
507 }
508
509 is_equal = true;
510
511 end:
512 return is_equal;
513 }
514
515 static
516 bool lttng_kernel_probe_location_symbol_is_equal(
517 const struct lttng_kernel_probe_location *_a,
518 const struct lttng_kernel_probe_location *_b)
519 {
520 bool is_equal = false;
521 struct lttng_kernel_probe_location_symbol *a, *b;
522
523 a = container_of(_a, struct lttng_kernel_probe_location_symbol,
524 parent);
525 b = container_of(_b, struct lttng_kernel_probe_location_symbol,
526 parent);
527
528 assert(a->symbol_name);
529 assert(b->symbol_name);
530 if (strcmp(a->symbol_name, b->symbol_name)) {
531 goto end;
532 }
533
534 if (a->offset != b->offset) {
535 goto end;
536 }
537
538 is_equal = true;
539
540 end:
541 return is_equal;
542 }
543
544 LTTNG_HIDDEN
545 bool lttng_kernel_probe_location_is_equal(
546 const struct lttng_kernel_probe_location *a,
547 const struct lttng_kernel_probe_location *b)
548 {
549 bool is_equal = false;
550
551 if (!a || !b) {
552 goto end;
553 }
554
555 if (a == b) {
556 is_equal = true;
557 goto end;
558 }
559
560 if (a->type != b->type) {
561 goto end;
562 }
563
564 is_equal = a->equal ? a->equal(a, b) : true;
565 end:
566 return is_equal;
567 }
568
569 static struct lttng_kernel_probe_location *
570 lttng_kernel_probe_location_symbol_copy(
571 const struct lttng_kernel_probe_location *location)
572 {
573 struct lttng_kernel_probe_location *new_location = NULL;
574 struct lttng_kernel_probe_location_symbol *symbol_location;
575 enum lttng_kernel_probe_location_status status;
576 const char *symbol_name = NULL;
577 uint64_t offset;
578
579 assert(location);
580 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
581 symbol_location = container_of(
582 location, typeof(*symbol_location), parent);
583
584 /* Get probe location offset */
585 status = lttng_kernel_probe_location_symbol_get_offset(location, &offset);
586 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
587 ERR("Get kernel probe location offset failed.");
588 goto error;
589 }
590
591 symbol_name = lttng_kernel_probe_location_symbol_get_name(location);
592 if (!symbol_name) {
593 ERR("Kernel probe symbol name is NULL.");
594 goto error;
595 }
596
597 /* Create the probe_location */
598 new_location = lttng_kernel_probe_location_symbol_create(
599 symbol_name, offset);
600
601 goto end;
602
603 error:
604 new_location = NULL;
605 end:
606 return new_location;
607 }
608 static struct lttng_kernel_probe_location *
609 lttng_kernel_probe_location_address_copy(
610 const struct lttng_kernel_probe_location *location)
611 {
612 struct lttng_kernel_probe_location *new_location = NULL;
613 struct lttng_kernel_probe_location_address *address_location;
614 enum lttng_kernel_probe_location_status status;
615 uint64_t address;
616
617 assert(location);
618 assert(location->type == LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
619 address_location = container_of(
620 location, typeof(*address_location), parent);
621
622
623 /* Get probe location fields */
624 status = lttng_kernel_probe_location_address_get_address(location, &address);
625 if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
626 ERR("Get kernel probe address failed.");
627 goto error;
628 }
629
630 /* Create the probe_location */
631 new_location = lttng_kernel_probe_location_address_create(address);
632
633 goto end;
634
635 error:
636 new_location = NULL;
637 end:
638 return new_location;
639 }
640
641 LTTNG_HIDDEN
642 struct lttng_kernel_probe_location *lttng_kernel_probe_location_copy(
643 const struct lttng_kernel_probe_location *location)
644 {
645 struct lttng_kernel_probe_location *new_location = NULL;
646 enum lttng_kernel_probe_location_type type;
647
648 if (!location) {
649 goto err;
650 }
651
652 type = lttng_kernel_probe_location_get_type(location);
653 switch (type) {
654 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
655 new_location =
656 lttng_kernel_probe_location_address_copy(location);
657 if (!new_location) {
658 goto err;
659 }
660 break;
661 case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
662 new_location =
663 lttng_kernel_probe_location_symbol_copy(location);
664 if (!new_location) {
665 goto err;
666 }
667 break;
668 default:
669 new_location = NULL;
670 goto err;
671 }
672 err:
673 return new_location;
674 }
This page took 0.064608 seconds and 3 git commands to generate.