X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-elf.c;h=5de3561fbeefcc71a56522f8763fb628dbdcede3;hb=fb31eb73d8a4a6d9784ed5c335b7fa3b9684108c;hp=e71436b422fd0ca202c3fc6ed65abc670774a6b9;hpb=5b3bbf983c555a7f3c2f8a901da842d07597c430;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-elf.c b/liblttng-ust/lttng-ust-elf.c index e71436b4..5de3561f 100644 --- a/liblttng-ust/lttng-ust-elf.c +++ b/liblttng-ust/lttng-ust-elf.c @@ -16,18 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE +#define _LGPL_SOURCE +#include #include -#include #include #include -#include +#include +#include +#include #include -#include +#include #include + +#include + #include "lttng-tracer-core.h" #define BUF_LEN 4096 +#ifndef NT_GNU_BUILD_ID +# define NT_GNU_BUILD_ID 3 +#endif + /* * Retrieve the nth (where n is the `index` argument) phdr (program * header) from the given elf instance. @@ -39,7 +50,7 @@ struct lttng_ust_elf_phdr *lttng_ust_elf_get_phdr(struct lttng_ust_elf *elf, uint16_t index) { struct lttng_ust_elf_phdr *phdr = NULL; - long offset; + off_t offset; if (!elf) { goto error; @@ -54,7 +65,8 @@ struct lttng_ust_elf_phdr *lttng_ust_elf_get_phdr(struct lttng_ust_elf *elf, goto error; } - offset = elf->ehdr->e_phoff + index * elf->ehdr->e_phentsize; + offset = (off_t) elf->ehdr->e_phoff + + (off_t) index * elf->ehdr->e_phentsize; if (lseek(elf->fd, offset, SEEK_SET) < 0) { goto error; } @@ -101,7 +113,7 @@ struct lttng_ust_elf_shdr *lttng_ust_elf_get_shdr(struct lttng_ust_elf *elf, uint16_t index) { struct lttng_ust_elf_shdr *shdr = NULL; - long offset; + off_t offset; if (!elf) { goto error; @@ -116,7 +128,8 @@ struct lttng_ust_elf_shdr *lttng_ust_elf_get_shdr(struct lttng_ust_elf *elf, goto error; } - offset = elf->ehdr->e_shoff + index * elf->ehdr->e_shentsize; + offset = (off_t) elf->ehdr->e_shoff + + (off_t) index * elf->ehdr->e_shentsize; if (lseek(elf->fd, offset, SEEK_SET) < 0) { goto error; } @@ -160,7 +173,7 @@ error: * If no name is found, NULL is returned. */ static -char *lttng_ust_elf_get_section_name(struct lttng_ust_elf *elf, uint32_t offset) +char *lttng_ust_elf_get_section_name(struct lttng_ust_elf *elf, off_t offset) { char *name = NULL; size_t len = 0, to_read; /* len does not include \0 */ @@ -233,22 +246,41 @@ struct lttng_ust_elf *lttng_ust_elf_create(const char *path) uint8_t e_ident[EI_NIDENT]; struct lttng_ust_elf_shdr *section_names_shdr; struct lttng_ust_elf *elf = NULL; + int ret, fd; elf = zmalloc(sizeof(struct lttng_ust_elf)); if (!elf) { goto error; } + /* Initialize fd field to -1. 0 is a valid fd number */ + elf->fd = -1; + elf->path = strdup(path); if (!elf->path) { goto error; } - elf->fd = open(elf->path, O_RDONLY | O_CLOEXEC); - if (elf->fd < 0) { + lttng_ust_lock_fd_tracker(); + fd = open(elf->path, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + lttng_ust_unlock_fd_tracker(); goto error; } + ret = lttng_ust_add_fd_to_tracker(fd); + if (ret < 0) { + ret = close(fd); + if (ret) { + PERROR("close on elf->fd"); + } + ret = -1; + lttng_ust_unlock_fd_tracker(); + goto error; + } + elf->fd = ret; + lttng_ust_unlock_fd_tracker(); + if (lttng_ust_read(elf->fd, e_ident, EI_NIDENT) < EI_NIDENT) { goto error; } @@ -300,32 +332,46 @@ struct lttng_ust_elf *lttng_ust_elf_create(const char *path) return elf; error: - if (elf) { - free(elf->ehdr); - if (elf->fd >= 0) { - if (close(elf->fd)) { - abort(); - } - } - free(elf->path); - free(elf); - } + lttng_ust_elf_destroy(elf); return NULL; } +/* + * Test whether the ELF file is position independent code (PIC) + */ +uint8_t lttng_ust_elf_is_pic(struct lttng_ust_elf *elf) +{ + /* + * PIC has and e_type value of ET_DYN, see ELF specification + * version 1.1 p. 1-3. + */ + return elf->ehdr->e_type == ET_DYN; +} + /* * Destroy the given lttng_ust_elf instance. */ void lttng_ust_elf_destroy(struct lttng_ust_elf *elf) { + int ret; + if (!elf) { return; } - free(elf->ehdr); - if (close(elf->fd)) { - abort(); + if (elf->fd >= 0) { + lttng_ust_lock_fd_tracker(); + ret = close(elf->fd); + if (!ret) { + lttng_ust_delete_fd_from_tracker(elf->fd); + } else { + PERROR("close"); + abort(); + } + lttng_ust_unlock_fd_tracker(); } + + free(elf->ehdr); free(elf->path); free(elf); } @@ -339,7 +385,7 @@ void lttng_ust_elf_destroy(struct lttng_ust_elf *elf) int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz) { uint16_t i; - uint64_t _memsz = 0; + uint64_t low_addr = UINT64_MAX, high_addr = 0; if (!elf || !memsz) { goto error; @@ -347,7 +393,6 @@ int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz) for (i = 0; i < elf->ehdr->e_phnum; ++i) { struct lttng_ust_elf_phdr *phdr; - uint64_t align; phdr = lttng_ust_elf_get_phdr(elf, i); if (!phdr) { @@ -362,27 +407,19 @@ int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz) goto next_loop; } - /* - * A p_align of 0 means no alignment, i.e. aligned to - * 1 byte. - */ - align = phdr->p_align == 0 ? 1 : phdr->p_align; - /* Align the start of the segment. */ - _memsz += offset_align(_memsz, align); - _memsz += phdr->p_memsz; - /* - * Add padding at the end of the segment, so it ends - * on a multiple of the align value (which usually - * means a page boundary). This makes the computation - * valid even in cases where p_align would change from - * one segment to the next. - */ - _memsz += offset_align(_memsz, align); + low_addr = min_t(uint64_t, low_addr, phdr->p_vaddr); + high_addr = max_t(uint64_t, high_addr, + phdr->p_vaddr + phdr->p_memsz); next_loop: free(phdr); } - *memsz = _memsz; + if (high_addr < low_addr) { + /* No PT_LOAD segments or corrupted data. */ + goto error; + } + + *memsz = high_addr - low_addr; return 0; error: return -1; @@ -403,11 +440,10 @@ error: static int lttng_ust_elf_get_build_id_from_segment( struct lttng_ust_elf *elf, uint8_t **build_id, size_t *length, - uint64_t offset, uint64_t segment_end, int *found) + off_t offset, off_t segment_end) { - uint8_t *_build_id; - size_t _length; - int _found = 0; + uint8_t *_build_id = NULL; /* Silence old gcc warning. */ + size_t _length = 0; /* Silence old gcc warning. */ while (offset < segment_end) { struct lttng_ust_elf_nhdr nhdr; @@ -452,7 +488,7 @@ int lttng_ust_elf_get_build_id_from_segment( _length = nhdr.n_descsz; _build_id = zmalloc(sizeof(uint8_t) * _length); - if (!build_id) { + if (!_build_id) { goto error; } @@ -464,18 +500,17 @@ int lttng_ust_elf_get_build_id_from_segment( goto error; } - _found = 1; break; } - if (_found) { + if (_build_id) { *build_id = _build_id; *length = _length; } - *found = _found; return 0; error: + free(_build_id); return -1; } @@ -496,16 +531,15 @@ int lttng_ust_elf_get_build_id(struct lttng_ust_elf *elf, uint8_t **build_id, size_t *length, int *found) { uint16_t i; - uint8_t *_build_id; - size_t _length; - int _found = 0; + uint8_t *_build_id = NULL; /* Silence old gcc warning. */ + size_t _length = 0; /* Silence old gcc warning. */ if (!elf || !build_id || !length || !found) { goto error; } for (i = 0; i < elf->ehdr->e_phnum; ++i) { - uint64_t offset, segment_end; + off_t offset, segment_end; struct lttng_ust_elf_phdr *phdr; int ret = 0; @@ -522,26 +556,28 @@ int lttng_ust_elf_get_build_id(struct lttng_ust_elf *elf, uint8_t **build_id, offset = phdr->p_offset; segment_end = offset + phdr->p_filesz; ret = lttng_ust_elf_get_build_id_from_segment( - elf, &_build_id, &_length, offset, segment_end, - &_found); + elf, &_build_id, &_length, offset, segment_end); next_loop: free(phdr); if (ret) { goto error; } - if (_found) { + if (_build_id) { break; } } - if (_found) { + if (_build_id) { *build_id = _build_id; *length = _length; + *found = 1; + } else { + *found = 0; } - *found = _found; return 0; error: + free(_build_id); return -1; } @@ -557,16 +593,14 @@ error: */ int lttng_ust_elf_get_debug_link_from_section(struct lttng_ust_elf *elf, char **filename, uint32_t *crc, - int *found, struct lttng_ust_elf_shdr *shdr) { - int _found = 0; - char *_filename; + char *_filename = NULL; /* Silence old gcc warning. */ size_t filename_len; char *section_name = NULL; - uint32_t _crc; + uint32_t _crc = 0; /* Silence old gcc warning. */ - if (!elf || !filename || !crc || !found || !shdr) { + if (!elf || !filename || !crc || !shdr) { goto error; } @@ -609,23 +643,18 @@ int lttng_ust_elf_get_debug_link_from_section(struct lttng_ust_elf *elf, _crc = bswap_32(_crc); } - _found = 1; - end: free(section_name); - if (_found) { + if (_filename) { *filename = _filename; *crc = _crc; } - *found = _found; return 0; error: - if (section_name) { - free(section_name); - } - + free(_filename); + free(section_name); return -1; } @@ -644,9 +673,8 @@ int lttng_ust_elf_get_debug_link(struct lttng_ust_elf *elf, char **filename, { int ret; uint16_t i; - int _found = 0; - char *_filename; - uint32_t _crc; + char *_filename = NULL; /* Silence old gcc warning. */ + uint32_t _crc = 0; /* Silence old gcc warning. */ if (!elf || !filename || !crc || !found) { goto error; @@ -661,24 +689,28 @@ int lttng_ust_elf_get_debug_link(struct lttng_ust_elf *elf, char **filename, } ret = lttng_ust_elf_get_debug_link_from_section( - elf, &_filename, &_crc, &_found, shdr); + elf, &_filename, &_crc, shdr); free(shdr); if (ret) { goto error; } - if (_found) { + if (_filename) { break; } } - if (_found) { + if (_filename) { *filename = _filename; *crc = _crc; + *found = 1; + } else { + *found = 0; } - *found = _found; return 0; + error: + free(_filename); return -1; }