Performance: split check deliver fast/slow paths
[lttng-ust.git] / liblttng-ust / lttng-ust-elf.c
CommitLineData
8e2aed3f
AB
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
aaf93c60 19#define _GNU_SOURCE
8e2aed3f
AB
20#include <helper.h>
21#include <string.h>
22#include <lttng/align.h>
23#include <lttng/ust-elf.h>
405be658
MD
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <unistd.h>
97c7c238 28#include <stdbool.h>
405be658
MD
29#include "lttng-tracer-core.h"
30
31#define BUF_LEN 4096
8e2aed3f
AB
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 */
39static
40struct 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;
f5a6717a 44 off_t offset;
8e2aed3f
AB
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
f5a6717a
MD
59 offset = (off_t) elf->ehdr->e_phoff
60 + (off_t) index * elf->ehdr->e_phentsize;
405be658 61 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
8e2aed3f
AB
62 goto error;
63 }
64
65 if (is_elf_32_bit(elf)) {
66 Elf32_Phdr elf_phdr;
67
405be658
MD
68 if (lttng_ust_read(elf->fd, &elf_phdr, sizeof(elf_phdr))
69 < sizeof(elf_phdr)) {
8e2aed3f
AB
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
405be658
MD
79 if (lttng_ust_read(elf->fd, &elf_phdr, sizeof(elf_phdr))
80 < sizeof(elf_phdr)) {
8e2aed3f
AB
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
91error:
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 */
102static
103struct 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;
4c5dac0d 107 off_t offset;
8e2aed3f
AB
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
4c5dac0d 122 offset = (off_t) elf->ehdr->e_shoff
5a26ac54 123 + (off_t) index * elf->ehdr->e_shentsize;
405be658 124 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
8e2aed3f
AB
125 goto error;
126 }
127
128 if (is_elf_32_bit(elf)) {
129 Elf32_Shdr elf_shdr;
130
405be658
MD
131 if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr))
132 < sizeof(elf_shdr)) {
8e2aed3f
AB
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
405be658
MD
142 if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr))
143 < sizeof(elf_shdr)) {
8e2aed3f
AB
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
154error:
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 */
166static
f5a6717a 167char *lttng_ust_elf_get_section_name(struct lttng_ust_elf *elf, off_t offset)
8e2aed3f
AB
168{
169 char *name = NULL;
405be658 170 size_t len = 0, to_read; /* len does not include \0 */
8e2aed3f
AB
171
172 if (!elf) {
173 goto error;
174 }
175
176 if (offset >= elf->section_names_size) {
177 goto error;
178 }
179
405be658 180 if (lseek(elf->fd, elf->section_names_offset + offset, SEEK_SET) < 0) {
8e2aed3f
AB
181 goto error;
182 }
405be658
MD
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) {
8e2aed3f 193 goto error;
8e2aed3f 194 }
405be658
MD
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;
8e2aed3f 208 }
8e2aed3f 209end:
405be658 210 name = zmalloc(sizeof(char) * (len + 1)); /* + 1 for \0 */
8e2aed3f
AB
211 if (!name) {
212 goto error;
213 }
405be658
MD
214 if (lseek(elf->fd, elf->section_names_offset + offset,
215 SEEK_SET) < 0) {
8e2aed3f
AB
216 goto error;
217 }
405be658 218 if (lttng_ust_read(elf->fd, name, len + 1) < len + 1) {
8e2aed3f
AB
219 goto error;
220 }
221
222 return name;
223
224error:
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 */
235struct 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;
405be658 239 struct lttng_ust_elf *elf = NULL;
8e2aed3f
AB
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
405be658
MD
251 elf->fd = open(elf->path, O_RDONLY | O_CLOEXEC);
252 if (elf->fd < 0) {
8e2aed3f
AB
253 goto error;
254 }
255
405be658 256 if (lttng_ust_read(elf->fd, e_ident, EI_NIDENT) < EI_NIDENT) {
8e2aed3f
AB
257 goto error;
258 }
259 elf->bitness = e_ident[EI_CLASS];
260 elf->endianness = e_ident[EI_DATA];
405be658
MD
261
262 if (lseek(elf->fd, 0, SEEK_SET) < 0) {
263 goto error;
264 }
8e2aed3f
AB
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
405be658
MD
274 if (lttng_ust_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr))
275 < sizeof(elf_ehdr)) {
8e2aed3f
AB
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
405be658
MD
285 if (lttng_ust_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr))
286 < sizeof(elf_ehdr)) {
8e2aed3f
AB
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);
8e2aed3f
AB
304 return elf;
305
306error:
307 if (elf) {
308 free(elf->ehdr);
405be658
MD
309 if (elf->fd >= 0) {
310 if (close(elf->fd)) {
311 abort();
312 }
313 }
8e2aed3f 314 free(elf->path);
405be658 315 free(elf);
8e2aed3f 316 }
8e2aed3f
AB
317 return NULL;
318}
319
f5eb039d
AB
320/*
321 * Test whether the ELF file is position independent code (PIC)
322 */
323uint8_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
8e2aed3f
AB
332/*
333 * Destroy the given lttng_ust_elf instance.
334 */
335void lttng_ust_elf_destroy(struct lttng_ust_elf *elf)
336{
337 if (!elf) {
338 return;
339 }
340
341 free(elf->ehdr);
405be658
MD
342 if (close(elf->fd)) {
343 abort();
344 }
8e2aed3f
AB
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 */
355int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz)
356{
357 uint16_t i;
e1f0c569 358 uint64_t low_addr = UINT64_MAX, high_addr = 0;
8e2aed3f
AB
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;
8e2aed3f
AB
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
8886accb
MD
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);
8e2aed3f
AB
383 next_loop:
384 free(phdr);
385 }
386
e1f0c569
AB
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;
8e2aed3f
AB
393 return 0;
394error:
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 */
410static
411int lttng_ust_elf_get_build_id_from_segment(
412 struct lttng_ust_elf *elf, uint8_t **build_id, size_t *length,
82ee1ee4 413 off_t offset, off_t segment_end)
8e2aed3f 414{
814d07b1
MD
415 uint8_t *_build_id = NULL; /* Silence old gcc warning. */
416 size_t _length = 0; /* Silence old gcc warning. */
8e2aed3f
AB
417
418 while (offset < segment_end) {
419 struct lttng_ust_elf_nhdr nhdr;
405be658 420 size_t read_len;
8e2aed3f
AB
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 */
405be658 432 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
8e2aed3f
AB
433 goto error;
434 }
405be658
MD
435 if (lttng_ust_read(elf->fd, &nhdr, sizeof(nhdr))
436 < sizeof(nhdr)) {
8e2aed3f
AB
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);
5ada26b4 461 if (!_build_id) {
8e2aed3f
AB
462 goto error;
463 }
464
405be658 465 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
8e2aed3f
AB
466 goto error;
467 }
405be658
MD
468 read_len = sizeof(*_build_id) * _length;
469 if (lttng_ust_read(elf->fd, _build_id, read_len) < read_len) {
8e2aed3f
AB
470 goto error;
471 }
472
8e2aed3f
AB
473 break;
474 }
475
82ee1ee4 476 if (_build_id) {
8e2aed3f
AB
477 *build_id = _build_id;
478 *length = _length;
479 }
480
8e2aed3f
AB
481 return 0;
482error:
83215d66 483 free(_build_id);
8e2aed3f
AB
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 */
500int 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;
8c83dbda
MD
504 uint8_t *_build_id = NULL; /* Silence old gcc warning. */
505 size_t _length = 0; /* Silence old gcc warning. */
8e2aed3f
AB
506
507 if (!elf || !build_id || !length || !found) {
508 goto error;
509 }
510
511 for (i = 0; i < elf->ehdr->e_phnum; ++i) {
f5a6717a 512 off_t offset, segment_end;
8e2aed3f 513 struct lttng_ust_elf_phdr *phdr;
5b3bbf98 514 int ret = 0;
8e2aed3f
AB
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(
82ee1ee4 529 elf, &_build_id, &_length, offset, segment_end);
8e2aed3f
AB
530 next_loop:
531 free(phdr);
532 if (ret) {
533 goto error;
534 }
82ee1ee4 535 if (_build_id) {
8e2aed3f
AB
536 break;
537 }
538 }
539
82ee1ee4 540 if (_build_id) {
8e2aed3f
AB
541 *build_id = _build_id;
542 *length = _length;
82ee1ee4
AB
543 *found = 1;
544 } else {
545 *found = 0;
8e2aed3f
AB
546 }
547
8e2aed3f
AB
548 return 0;
549error:
99b7132d 550 free(_build_id);
8e2aed3f
AB
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 */
8e2aed3f
AB
564int lttng_ust_elf_get_debug_link_from_section(struct lttng_ust_elf *elf,
565 char **filename, uint32_t *crc,
8e2aed3f
AB
566 struct lttng_ust_elf_shdr *shdr)
567{
8c83dbda 568 char *_filename = NULL; /* Silence old gcc warning. */
405be658 569 size_t filename_len;
8e2aed3f 570 char *section_name = NULL;
8c83dbda 571 uint32_t _crc = 0; /* Silence old gcc warning. */
8e2aed3f 572
82ee1ee4 573 if (!elf || !filename || !crc || !shdr) {
8e2aed3f
AB
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 }
405be658 602 if (lseek(elf->fd, shdr->sh_offset, SEEK_SET) < 0) {
8e2aed3f
AB
603 goto error;
604 }
405be658
MD
605 filename_len = sizeof(*_filename) * (shdr->sh_size - ELF_CRC_SIZE);
606 if (lttng_ust_read(elf->fd, _filename, filename_len) < filename_len) {
8e2aed3f
AB
607 goto error;
608 }
405be658 609 if (lttng_ust_read(elf->fd, &_crc, sizeof(_crc)) < sizeof(_crc)) {
8e2aed3f
AB
610 goto error;
611 }
612 if (!is_elf_native_endian(elf)) {
613 _crc = bswap_32(_crc);
614 }
615
8e2aed3f
AB
616end:
617 free(section_name);
82ee1ee4 618 if (_filename) {
8e2aed3f
AB
619 *filename = _filename;
620 *crc = _crc;
621 }
8e2aed3f
AB
622
623 return 0;
624
625error:
83215d66
MD
626 free(_filename);
627 free(section_name);
8e2aed3f
AB
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 */
641int 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;
8c83dbda
MD
646 char *_filename = NULL; /* Silence old gcc warning. */
647 uint32_t _crc = 0; /* Silence old gcc warning. */
8e2aed3f
AB
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(
82ee1ee4 662 elf, &_filename, &_crc, shdr);
8e2aed3f
AB
663 free(shdr);
664
665 if (ret) {
666 goto error;
667 }
82ee1ee4 668 if (_filename) {
8e2aed3f
AB
669 break;
670 }
671 }
672
82ee1ee4 673 if (_filename) {
8e2aed3f
AB
674 *filename = _filename;
675 *crc = _crc;
82ee1ee4
AB
676 *found = 1;
677 } else {
678 *found = 0;
8e2aed3f
AB
679 }
680
8e2aed3f 681 return 0;
82ee1ee4 682
8e2aed3f 683error:
99b7132d 684 free(_filename);
8e2aed3f
AB
685 return -1;
686}
This page took 0.052445 seconds and 4 git commands to generate.