#ifndef _LTTNG_UST_ELF_H #define _LTTNG_UST_ELF_H /* * Copyright (C) 2015 Antoine Busque * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include /* * Determine native endianness in order to convert when reading an ELF * file if there is a mismatch. */ #if BYTE_ORDER == LITTLE_ENDIAN #define NATIVE_ELF_ENDIANNESS ELFDATA2LSB #else #define NATIVE_ELF_ENDIANNESS ELFDATA2MSB #endif /* * The size in bytes of the debug link CRC as contained in an ELF * section. */ #define ELF_CRC_SIZE 4 /* * ELF notes are aligned on 4 bytes. ref: ELF specification version * 1.1 p. 2-5. */ #define ELF_NOTE_ENTRY_ALIGN 4 /* * Within an ELF note, the `desc` field is also aligned on 4 * bytes. ref: ELF specification version 1.1 p. 2-5. */ #define ELF_NOTE_DESC_ALIGN 4 #define bswap(x) \ do { \ switch (sizeof(x)) { \ case 8: \ x = bswap_64(x); \ break; \ case 4: \ x = bswap_32(x); \ break; \ case 2: \ x = bswap_16(x); \ break; \ case 1: \ break; \ default: \ abort(); \ } \ } while (0) #define bswap_phdr(phdr) \ do { \ bswap((phdr).p_type); \ bswap((phdr).p_offset); \ bswap((phdr).p_filesz); \ bswap((phdr).p_memsz); \ bswap((phdr).p_align); \ bswap((phdr).p_vaddr); \ } while (0) #define bswap_shdr(shdr) \ do { \ bswap((shdr).sh_name); \ bswap((shdr).sh_type); \ bswap((shdr).sh_flags); \ bswap((shdr).sh_addr); \ bswap((shdr).sh_offset); \ bswap((shdr).sh_size); \ bswap((shdr).sh_link); \ bswap((shdr).sh_info); \ bswap((shdr).sh_addralign); \ bswap((shdr).sh_entsize); \ } while (0) #define bswap_ehdr(ehdr) \ do { \ bswap((ehdr).e_type); \ bswap((ehdr).e_machine); \ bswap((ehdr).e_version); \ bswap((ehdr).e_entry); \ bswap((ehdr).e_phoff); \ bswap((ehdr).e_shoff); \ bswap((ehdr).e_flags); \ bswap((ehdr).e_ehsize); \ bswap((ehdr).e_phentsize); \ bswap((ehdr).e_phnum); \ bswap((ehdr).e_shentsize); \ bswap((ehdr).e_shnum); \ bswap((ehdr).e_shstrndx); \ } while (0) #define copy_phdr(src_phdr, dst_phdr) \ do { \ (dst_phdr).p_type = (src_phdr).p_type; \ (dst_phdr).p_offset = (src_phdr).p_offset; \ (dst_phdr).p_filesz = (src_phdr).p_filesz; \ (dst_phdr).p_memsz = (src_phdr).p_memsz; \ (dst_phdr).p_align = (src_phdr).p_align; \ (dst_phdr).p_vaddr = (src_phdr).p_vaddr; \ } while (0) #define copy_shdr(src_shdr, dst_shdr) \ do { \ (dst_shdr).sh_name = (src_shdr).sh_name; \ (dst_shdr).sh_type = (src_shdr).sh_type; \ (dst_shdr).sh_flags = (src_shdr).sh_flags; \ (dst_shdr).sh_addr = (src_shdr).sh_addr; \ (dst_shdr).sh_offset = (src_shdr).sh_offset; \ (dst_shdr).sh_size = (src_shdr).sh_size; \ (dst_shdr).sh_link = (src_shdr).sh_link; \ (dst_shdr).sh_info = (src_shdr).sh_info; \ (dst_shdr).sh_addralign = (src_shdr).sh_addralign; \ (dst_shdr).sh_entsize = (src_shdr).sh_entsize; \ } while (0) #define copy_ehdr(src_ehdr, dst_ehdr) \ do { \ (dst_ehdr).e_type = (src_ehdr).e_type; \ (dst_ehdr).e_machine = (src_ehdr).e_machine; \ (dst_ehdr).e_version = (src_ehdr).e_version; \ (dst_ehdr).e_entry = (src_ehdr).e_entry; \ (dst_ehdr).e_phoff = (src_ehdr).e_phoff; \ (dst_ehdr).e_shoff = (src_ehdr).e_shoff; \ (dst_ehdr).e_flags = (src_ehdr).e_flags; \ (dst_ehdr).e_ehsize = (src_ehdr).e_ehsize; \ (dst_ehdr).e_phentsize = (src_ehdr).e_phentsize; \ (dst_ehdr).e_phnum = (src_ehdr).e_phnum; \ (dst_ehdr).e_shentsize = (src_ehdr).e_shentsize; \ (dst_ehdr).e_shnum = (src_ehdr).e_shnum; \ (dst_ehdr).e_shstrndx = (src_ehdr).e_shstrndx; \ } while (0) struct lttng_ust_elf_ehdr { uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint64_t e_entry; uint64_t e_phoff; uint64_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; }; struct lttng_ust_elf_phdr { uint32_t p_type; uint64_t p_offset; uint64_t p_filesz; uint64_t p_memsz; uint64_t p_align; uint64_t p_vaddr; }; struct lttng_ust_elf_shdr { uint32_t sh_name; uint32_t sh_type; uint64_t sh_flags; uint64_t sh_addr; uint64_t sh_offset; uint64_t sh_size; uint32_t sh_link; uint32_t sh_info; uint64_t sh_addralign; uint64_t sh_entsize; }; struct lttng_ust_elf_nhdr { uint32_t n_namesz; uint32_t n_descsz; uint32_t n_type; }; struct lttng_ust_elf { /* Offset in bytes to start of section names string table. */ off_t section_names_offset; /* Size in bytes of section names string table. */ size_t section_names_size; char *path; int fd; struct lttng_ust_elf_ehdr *ehdr; uint8_t bitness; uint8_t endianness; }; static inline int is_elf_32_bit(struct lttng_ust_elf *elf) { return elf->bitness == ELFCLASS32; } static inline int is_elf_native_endian(struct lttng_ust_elf *elf) { return elf->endianness == NATIVE_ELF_ENDIANNESS; } struct lttng_ust_elf *lttng_ust_elf_create(const char *path); void lttng_ust_elf_destroy(struct lttng_ust_elf *elf); uint8_t lttng_ust_elf_is_pic(struct lttng_ust_elf *elf); int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz); int lttng_ust_elf_get_build_id(struct lttng_ust_elf *elf, uint8_t **build_id, size_t *length, int *found); int lttng_ust_elf_get_debug_link(struct lttng_ust_elf *elf, char **filename, uint32_t *crc, int *found); #endif /* _LTTNG_UST_ELF_H */