Add library load/unload tracking events
[lttng-ust.git] / liblttng-ust / lttng-ust-elf.c
1 /*
2 * Copyright (C) 2015 Antoine Busque <abusque@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #define _GNU_SOURCE
20 #include <helper.h>
21 #include <string.h>
22 #include <lttng/align.h>
23 #include <lttng/ust-elf.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <stdbool.h>
29 #include "lttng-tracer-core.h"
30
31 #define BUF_LEN 4096
32
33 /*
34 * Retrieve the nth (where n is the `index` argument) phdr (program
35 * header) from the given elf instance.
36 *
37 * A pointer to the phdr is returned on success, NULL on failure.
38 */
39 static
40 struct lttng_ust_elf_phdr *lttng_ust_elf_get_phdr(struct lttng_ust_elf *elf,
41 uint16_t index)
42 {
43 struct lttng_ust_elf_phdr *phdr = NULL;
44 off_t offset;
45
46 if (!elf) {
47 goto error;
48 }
49
50 if (index >= elf->ehdr->e_phnum) {
51 goto error;
52 }
53
54 phdr = zmalloc(sizeof(struct lttng_ust_elf_phdr));
55 if (!phdr) {
56 goto error;
57 }
58
59 offset = (off_t) elf->ehdr->e_phoff
60 + (off_t) index * elf->ehdr->e_phentsize;
61 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
62 goto error;
63 }
64
65 if (is_elf_32_bit(elf)) {
66 Elf32_Phdr elf_phdr;
67
68 if (lttng_ust_read(elf->fd, &elf_phdr, sizeof(elf_phdr))
69 < sizeof(elf_phdr)) {
70 goto error;
71 }
72 if (!is_elf_native_endian(elf)) {
73 bswap_phdr(elf_phdr);
74 }
75 copy_phdr(elf_phdr, *phdr);
76 } else {
77 Elf64_Phdr elf_phdr;
78
79 if (lttng_ust_read(elf->fd, &elf_phdr, sizeof(elf_phdr))
80 < sizeof(elf_phdr)) {
81 goto error;
82 }
83 if (!is_elf_native_endian(elf)) {
84 bswap_phdr(elf_phdr);
85 }
86 copy_phdr(elf_phdr, *phdr);
87 }
88
89 return phdr;
90
91 error:
92 free(phdr);
93 return NULL;
94 }
95
96 /*
97 * Retrieve the nth (where n is the `index` argument) shdr (section
98 * header) from the given elf instance.
99 *
100 * A pointer to the shdr is returned on success, NULL on failure.
101 */
102 static
103 struct lttng_ust_elf_shdr *lttng_ust_elf_get_shdr(struct lttng_ust_elf *elf,
104 uint16_t index)
105 {
106 struct lttng_ust_elf_shdr *shdr = NULL;
107 off_t offset;
108
109 if (!elf) {
110 goto error;
111 }
112
113 if (index >= elf->ehdr->e_shnum) {
114 goto error;
115 }
116
117 shdr = zmalloc(sizeof(struct lttng_ust_elf_shdr));
118 if (!shdr) {
119 goto error;
120 }
121
122 offset = (off_t) elf->ehdr->e_shoff
123 + (off_t) index * elf->ehdr->e_shentsize;
124 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
125 goto error;
126 }
127
128 if (is_elf_32_bit(elf)) {
129 Elf32_Shdr elf_shdr;
130
131 if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr))
132 < sizeof(elf_shdr)) {
133 goto error;
134 }
135 if (!is_elf_native_endian(elf)) {
136 bswap_shdr(elf_shdr);
137 }
138 copy_shdr(elf_shdr, *shdr);
139 } else {
140 Elf64_Shdr elf_shdr;
141
142 if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr))
143 < sizeof(elf_shdr)) {
144 goto error;
145 }
146 if (!is_elf_native_endian(elf)) {
147 bswap_shdr(elf_shdr);
148 }
149 copy_shdr(elf_shdr, *shdr);
150 }
151
152 return shdr;
153
154 error:
155 free(shdr);
156 return NULL;
157 }
158
159 /*
160 * Lookup a section's name from a given offset (usually from an shdr's
161 * sh_name value) in bytes relative to the beginning of the section
162 * names string table.
163 *
164 * If no name is found, NULL is returned.
165 */
166 static
167 char *lttng_ust_elf_get_section_name(struct lttng_ust_elf *elf, off_t offset)
168 {
169 char *name = NULL;
170 size_t len = 0, to_read; /* len does not include \0 */
171
172 if (!elf) {
173 goto error;
174 }
175
176 if (offset >= elf->section_names_size) {
177 goto error;
178 }
179
180 if (lseek(elf->fd, elf->section_names_offset + offset, SEEK_SET) < 0) {
181 goto error;
182 }
183
184 to_read = elf->section_names_size - offset;
185
186 /* Find first \0 after or at current location, remember len. */
187 for (;;) {
188 char buf[BUF_LEN];
189 ssize_t read_len;
190 size_t i;
191
192 if (!to_read) {
193 goto error;
194 }
195 read_len = lttng_ust_read(elf->fd, buf,
196 min_t(size_t, BUF_LEN, to_read));
197 if (read_len <= 0) {
198 goto error;
199 }
200 for (i = 0; i < read_len; i++) {
201 if (buf[i] == '\0') {
202 len += i;
203 goto end;
204 }
205 }
206 len += read_len;
207 to_read -= read_len;
208 }
209 end:
210 name = zmalloc(sizeof(char) * (len + 1)); /* + 1 for \0 */
211 if (!name) {
212 goto error;
213 }
214 if (lseek(elf->fd, elf->section_names_offset + offset,
215 SEEK_SET) < 0) {
216 goto error;
217 }
218 if (lttng_ust_read(elf->fd, name, len + 1) < len + 1) {
219 goto error;
220 }
221
222 return name;
223
224 error:
225 free(name);
226 return NULL;
227 }
228
229 /*
230 * Create an instance of lttng_ust_elf for the ELF file located at
231 * `path`.
232 *
233 * Return a pointer to the instance on success, NULL on failure.
234 */
235 struct lttng_ust_elf *lttng_ust_elf_create(const char *path)
236 {
237 uint8_t e_ident[EI_NIDENT];
238 struct lttng_ust_elf_shdr *section_names_shdr;
239 struct lttng_ust_elf *elf = NULL;
240
241 elf = zmalloc(sizeof(struct lttng_ust_elf));
242 if (!elf) {
243 goto error;
244 }
245
246 elf->path = strdup(path);
247 if (!elf->path) {
248 goto error;
249 }
250
251 elf->fd = open(elf->path, O_RDONLY | O_CLOEXEC);
252 if (elf->fd < 0) {
253 goto error;
254 }
255
256 if (lttng_ust_read(elf->fd, e_ident, EI_NIDENT) < EI_NIDENT) {
257 goto error;
258 }
259 elf->bitness = e_ident[EI_CLASS];
260 elf->endianness = e_ident[EI_DATA];
261
262 if (lseek(elf->fd, 0, SEEK_SET) < 0) {
263 goto error;
264 }
265
266 elf->ehdr = zmalloc(sizeof(struct lttng_ust_elf_ehdr));
267 if (!elf->ehdr) {
268 goto error;
269 }
270
271 if (is_elf_32_bit(elf)) {
272 Elf32_Ehdr elf_ehdr;
273
274 if (lttng_ust_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr))
275 < sizeof(elf_ehdr)) {
276 goto error;
277 }
278 if (!is_elf_native_endian(elf)) {
279 bswap_ehdr(elf_ehdr);
280 }
281 copy_ehdr(elf_ehdr, *(elf->ehdr));
282 } else {
283 Elf64_Ehdr elf_ehdr;
284
285 if (lttng_ust_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr))
286 < sizeof(elf_ehdr)) {
287 goto error;
288 }
289 if (!is_elf_native_endian(elf)) {
290 bswap_ehdr(elf_ehdr);
291 }
292 copy_ehdr(elf_ehdr, *(elf->ehdr));
293 }
294
295 section_names_shdr = lttng_ust_elf_get_shdr(elf, elf->ehdr->e_shstrndx);
296 if (!section_names_shdr) {
297 goto error;
298 }
299
300 elf->section_names_offset = section_names_shdr->sh_offset;
301 elf->section_names_size = section_names_shdr->sh_size;
302
303 free(section_names_shdr);
304 return elf;
305
306 error:
307 if (elf) {
308 free(elf->ehdr);
309 if (elf->fd >= 0) {
310 if (close(elf->fd)) {
311 abort();
312 }
313 }
314 free(elf->path);
315 free(elf);
316 }
317 return NULL;
318 }
319
320 /*
321 * Test whether the ELF file is position independent code (PIC)
322 */
323 uint8_t lttng_ust_elf_is_pic(struct lttng_ust_elf *elf)
324 {
325 /*
326 * PIC has and e_type value of ET_DYN, see ELF specification
327 * version 1.1 p. 1-3.
328 */
329 return elf->ehdr->e_type == ET_DYN;
330 }
331
332 /*
333 * Destroy the given lttng_ust_elf instance.
334 */
335 void lttng_ust_elf_destroy(struct lttng_ust_elf *elf)
336 {
337 if (!elf) {
338 return;
339 }
340
341 free(elf->ehdr);
342 if (close(elf->fd)) {
343 abort();
344 }
345 free(elf->path);
346 free(elf);
347 }
348
349 /*
350 * Compute the total in-memory size of the ELF file, in bytes.
351 *
352 * Returns 0 if successful, -1 if not. On success, the memory size is
353 * returned through the out parameter `memsz`.
354 */
355 int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz)
356 {
357 uint16_t i;
358 uint64_t low_addr = UINT64_MAX, high_addr = 0;
359
360 if (!elf || !memsz) {
361 goto error;
362 }
363
364 for (i = 0; i < elf->ehdr->e_phnum; ++i) {
365 struct lttng_ust_elf_phdr *phdr;
366
367 phdr = lttng_ust_elf_get_phdr(elf, i);
368 if (!phdr) {
369 goto error;
370 }
371
372 /*
373 * Only PT_LOAD segments contribute to memsz. Skip
374 * other segments.
375 */
376 if (phdr->p_type != PT_LOAD) {
377 goto next_loop;
378 }
379
380 low_addr = min_t(uint64_t, low_addr, phdr->p_vaddr);
381 high_addr = max_t(uint64_t, high_addr,
382 phdr->p_vaddr + phdr->p_memsz);
383 next_loop:
384 free(phdr);
385 }
386
387 if (high_addr < low_addr) {
388 /* No PT_LOAD segments or corrupted data. */
389 goto error;
390 }
391
392 *memsz = high_addr - low_addr;
393 return 0;
394 error:
395 return -1;
396 }
397
398 /*
399 * Internal method used to try and get the build_id from a PT_NOTE
400 * segment ranging from `offset` to `segment_end`.
401 *
402 * If the function returns successfully, the out parameter `found`
403 * indicates whether the build id information was present in the
404 * segment or not. If `found` is not 0, the out parameters `build_id`
405 * and `length` will both have been set with the retrieved
406 * information.
407 *
408 * Returns 0 on success, -1 if an error occurred.
409 */
410 static
411 int lttng_ust_elf_get_build_id_from_segment(
412 struct lttng_ust_elf *elf, uint8_t **build_id, size_t *length,
413 off_t offset, off_t segment_end)
414 {
415 uint8_t *_build_id = NULL; /* Silence old gcc warning. */
416 size_t _length = 0; /* Silence old gcc warning. */
417
418 while (offset < segment_end) {
419 struct lttng_ust_elf_nhdr nhdr;
420 size_t read_len;
421
422 /* Align start of note entry */
423 offset += offset_align(offset, ELF_NOTE_ENTRY_ALIGN);
424 if (offset >= segment_end) {
425 break;
426 }
427 /*
428 * We seek manually because if the note isn't the
429 * build id the data following the header will not
430 * have been read.
431 */
432 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
433 goto error;
434 }
435 if (lttng_ust_read(elf->fd, &nhdr, sizeof(nhdr))
436 < sizeof(nhdr)) {
437 goto error;
438 }
439
440 if (!is_elf_native_endian(elf)) {
441 nhdr.n_namesz = bswap_32(nhdr.n_namesz);
442 nhdr.n_descsz = bswap_32(nhdr.n_descsz);
443 nhdr.n_type = bswap_32(nhdr.n_type);
444 }
445
446 offset += sizeof(nhdr) + nhdr.n_namesz;
447 /* Align start of desc entry */
448 offset += offset_align(offset, ELF_NOTE_DESC_ALIGN);
449
450 if (nhdr.n_type != NT_GNU_BUILD_ID) {
451 /*
452 * Ignore non build id notes but still
453 * increase the offset.
454 */
455 offset += nhdr.n_descsz;
456 continue;
457 }
458
459 _length = nhdr.n_descsz;
460 _build_id = zmalloc(sizeof(uint8_t) * _length);
461 if (!_build_id) {
462 goto error;
463 }
464
465 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
466 goto error;
467 }
468 read_len = sizeof(*_build_id) * _length;
469 if (lttng_ust_read(elf->fd, _build_id, read_len) < read_len) {
470 goto error;
471 }
472
473 break;
474 }
475
476 if (_build_id) {
477 *build_id = _build_id;
478 *length = _length;
479 }
480
481 return 0;
482 error:
483 free(_build_id);
484 return -1;
485 }
486
487 /*
488 * Retrieve a build ID (an array of bytes) from the corresponding
489 * section in the ELF file. The length of the build ID can be either
490 * 16 or 20 bytes depending on the method used to generate it, hence
491 * the length out parameter.
492 *
493 * If the function returns successfully, the out parameter `found`
494 * indicates whether the build id information was present in the ELF
495 * file or not. If `found` is not 0, the out parameters `build_id` and
496 * `length` will both have been set with the retrieved information.
497 *
498 * Returns 0 on success, -1 if an error occurred.
499 */
500 int lttng_ust_elf_get_build_id(struct lttng_ust_elf *elf, uint8_t **build_id,
501 size_t *length, int *found)
502 {
503 uint16_t i;
504 uint8_t *_build_id = NULL; /* Silence old gcc warning. */
505 size_t _length = 0; /* Silence old gcc warning. */
506
507 if (!elf || !build_id || !length || !found) {
508 goto error;
509 }
510
511 for (i = 0; i < elf->ehdr->e_phnum; ++i) {
512 off_t offset, segment_end;
513 struct lttng_ust_elf_phdr *phdr;
514 int ret = 0;
515
516 phdr = lttng_ust_elf_get_phdr(elf, i);
517 if (!phdr) {
518 goto error;
519 }
520
521 /* Build ID will be contained in a PT_NOTE segment. */
522 if (phdr->p_type != PT_NOTE) {
523 goto next_loop;
524 }
525
526 offset = phdr->p_offset;
527 segment_end = offset + phdr->p_filesz;
528 ret = lttng_ust_elf_get_build_id_from_segment(
529 elf, &_build_id, &_length, offset, segment_end);
530 next_loop:
531 free(phdr);
532 if (ret) {
533 goto error;
534 }
535 if (_build_id) {
536 break;
537 }
538 }
539
540 if (_build_id) {
541 *build_id = _build_id;
542 *length = _length;
543 *found = 1;
544 } else {
545 *found = 0;
546 }
547
548 return 0;
549 error:
550 free(_build_id);
551 return -1;
552 }
553
554 /*
555 * Try to retrieve filename and CRC from given ELF section `shdr`.
556 *
557 * If the function returns successfully, the out parameter `found`
558 * indicates whether the debug link information was present in the ELF
559 * section or not. If `found` is not 0, the out parameters `filename` and
560 * `crc` will both have been set with the retrieved information.
561 *
562 * Returns 0 on success, -1 if an error occurred.
563 */
564 int lttng_ust_elf_get_debug_link_from_section(struct lttng_ust_elf *elf,
565 char **filename, uint32_t *crc,
566 struct lttng_ust_elf_shdr *shdr)
567 {
568 char *_filename = NULL; /* Silence old gcc warning. */
569 size_t filename_len;
570 char *section_name = NULL;
571 uint32_t _crc = 0; /* Silence old gcc warning. */
572
573 if (!elf || !filename || !crc || !shdr) {
574 goto error;
575 }
576
577 /*
578 * The .gnu_debuglink section is of type SHT_PROGBITS,
579 * skip the other sections.
580 */
581 if (shdr->sh_type != SHT_PROGBITS) {
582 goto end;
583 }
584
585 section_name = lttng_ust_elf_get_section_name(elf,
586 shdr->sh_name);
587 if (!section_name) {
588 goto end;
589 }
590 if (strcmp(section_name, ".gnu_debuglink")) {
591 goto end;
592 }
593
594 /*
595 * The length of the filename is the sh_size excluding the CRC
596 * which comes after it in the section.
597 */
598 _filename = zmalloc(sizeof(char) * (shdr->sh_size - ELF_CRC_SIZE));
599 if (!_filename) {
600 goto error;
601 }
602 if (lseek(elf->fd, shdr->sh_offset, SEEK_SET) < 0) {
603 goto error;
604 }
605 filename_len = sizeof(*_filename) * (shdr->sh_size - ELF_CRC_SIZE);
606 if (lttng_ust_read(elf->fd, _filename, filename_len) < filename_len) {
607 goto error;
608 }
609 if (lttng_ust_read(elf->fd, &_crc, sizeof(_crc)) < sizeof(_crc)) {
610 goto error;
611 }
612 if (!is_elf_native_endian(elf)) {
613 _crc = bswap_32(_crc);
614 }
615
616 end:
617 free(section_name);
618 if (_filename) {
619 *filename = _filename;
620 *crc = _crc;
621 }
622
623 return 0;
624
625 error:
626 free(_filename);
627 free(section_name);
628 return -1;
629 }
630
631 /*
632 * Retrieve filename and CRC from ELF's .gnu_debuglink section, if any.
633 *
634 * If the function returns successfully, the out parameter `found`
635 * indicates whether the debug link information was present in the ELF
636 * file or not. If `found` is not 0, the out parameters `filename` and
637 * `crc` will both have been set with the retrieved information.
638 *
639 * Returns 0 on success, -1 if an error occurred.
640 */
641 int lttng_ust_elf_get_debug_link(struct lttng_ust_elf *elf, char **filename,
642 uint32_t *crc, int *found)
643 {
644 int ret;
645 uint16_t i;
646 char *_filename = NULL; /* Silence old gcc warning. */
647 uint32_t _crc = 0; /* Silence old gcc warning. */
648
649 if (!elf || !filename || !crc || !found) {
650 goto error;
651 }
652
653 for (i = 0; i < elf->ehdr->e_shnum; ++i) {
654 struct lttng_ust_elf_shdr *shdr = NULL;
655
656 shdr = lttng_ust_elf_get_shdr(elf, i);
657 if (!shdr) {
658 goto error;
659 }
660
661 ret = lttng_ust_elf_get_debug_link_from_section(
662 elf, &_filename, &_crc, shdr);
663 free(shdr);
664
665 if (ret) {
666 goto error;
667 }
668 if (_filename) {
669 break;
670 }
671 }
672
673 if (_filename) {
674 *filename = _filename;
675 *crc = _crc;
676 *found = 1;
677 } else {
678 *found = 0;
679 }
680
681 return 0;
682
683 error:
684 free(_filename);
685 return -1;
686 }
This page took 0.049271 seconds and 5 git commands to generate.