diff options
Diffstat (limited to 'ptxed/src/load_elf.c')
| -rw-r--r-- | ptxed/src/load_elf.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/ptxed/src/load_elf.c b/ptxed/src/load_elf.c new file mode 100644 index 000000000000..46e06d17a114 --- /dev/null +++ b/ptxed/src/load_elf.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "load_elf.h" + +#include "intel-pt.h" + +#include <stdio.h> +#include <elf.h> +#include <inttypes.h> +#include <errno.h> +#include <string.h> +#include <limits.h> + + +static int load_section(struct pt_image_section_cache *iscache, + struct pt_image *image, const char *name, + uint64_t offset, uint64_t size, uint64_t vaddr) +{ + if (!iscache) + return pt_image_add_file(image, name, offset, size, NULL, + vaddr); + else { + int isid; + + isid = pt_iscache_add_file(iscache, name, offset, size, vaddr); + if (isid < 0) + return isid; + + return pt_image_add_cached(image, iscache, isid, NULL); + } +} + +static int load_elf32(struct pt_image_section_cache *iscache, + struct pt_image *image, FILE *file, uint64_t base, + const char *name, const char *prog, int verbose) +{ + Elf32_Ehdr ehdr; + Elf32_Half pidx; + uint64_t offset; + size_t count; + int errcode, sections; + + errcode = fseek(file, 0, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking ELF header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + count = fread(&ehdr, sizeof(ehdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading ELF header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + errcode = fseek(file, (long) ehdr.e_phoff, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking program header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + /* Determine the load offset. */ + if (!base) + offset = 0; + else { + uint64_t minaddr; + + minaddr = UINT64_MAX; + + for (pidx = 0; pidx < ehdr.e_phnum; ++pidx) { + Elf32_Phdr phdr; + + count = fread(&phdr, sizeof(phdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading " + "phdr %u: %s.\n", + prog, name, pidx, strerror(errno)); + return -pte_bad_config; + } + + if (phdr.p_type != PT_LOAD) + continue; + + if (phdr.p_vaddr < minaddr) + minaddr = phdr.p_vaddr; + } + + offset = base - minaddr; + } + + errcode = fseek(file, (long) ehdr.e_phoff, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking program header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + for (sections = 0, pidx = 0; pidx < ehdr.e_phnum; ++pidx) { + Elf32_Phdr phdr; + + count = fread(&phdr, sizeof(phdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading phdr %u: %s.\n", + prog, name, pidx, strerror(errno)); + return -pte_bad_config; + } + + if (phdr.p_type != PT_LOAD) + continue; + + if (!phdr.p_filesz) + continue; + + errcode = load_section(iscache, image, name, phdr.p_offset, + phdr.p_filesz, phdr.p_vaddr + offset); + if (errcode < 0) { + fprintf(stderr, "%s: warning: %s: failed to create " + "section for phdr %u: %s.\n", prog, name, pidx, + pt_errstr(pt_errcode(errcode))); + continue; + } + + sections += 1; + + if (verbose) { + printf("%s:", name); + printf(" offset=0x%" PRIx32, phdr.p_offset); + printf(" size=0x%" PRIx32, phdr.p_filesz); + printf(" vaddr=0x%" PRIx32, phdr.p_vaddr); + printf(".\n"); + } + } + + if (!sections) + fprintf(stderr, + "%s: warning: %s: did not find any load sections.\n", + prog, name); + + return 0; +} + +static int load_elf64(struct pt_image_section_cache *iscache, + struct pt_image *image, FILE *file, uint64_t base, + const char *name, const char *prog, int verbose) +{ + Elf64_Ehdr ehdr; + Elf64_Half pidx; + uint64_t offset; + size_t count; + int errcode, sections; + + errcode = fseek(file, 0, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking ELF header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + count = fread(&ehdr, sizeof(ehdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading ELF header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + if (LONG_MAX < ehdr.e_phoff) { + fprintf(stderr, "%s: warning: %s ELF header too big.\n", + prog, name); + return -pte_bad_config; + } + + errcode = fseek(file, (long) ehdr.e_phoff, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking program header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + /* Determine the load offset. */ + if (!base) + offset = 0; + else { + uint64_t minaddr; + + minaddr = UINT64_MAX; + + for (pidx = 0; pidx < ehdr.e_phnum; ++pidx) { + Elf64_Phdr phdr; + + count = fread(&phdr, sizeof(phdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading " + "phdr %u: %s.\n", + prog, name, pidx, strerror(errno)); + return -pte_bad_config; + } + + if (phdr.p_type != PT_LOAD) + continue; + + if (phdr.p_vaddr < minaddr) + minaddr = phdr.p_vaddr; + } + + offset = base - minaddr; + } + + errcode = fseek(file, (long) ehdr.e_phoff, SEEK_SET); + if (errcode) { + fprintf(stderr, + "%s: warning: %s error seeking program header: %s.\n", + prog, name, strerror(errno)); + return -pte_bad_config; + } + + for (sections = 0, pidx = 0; pidx < ehdr.e_phnum; ++pidx) { + Elf64_Phdr phdr; + + count = fread(&phdr, sizeof(phdr), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s error reading phdr %u: %s.\n", + prog, name, pidx, strerror(errno)); + return -pte_bad_config; + } + + if (phdr.p_type != PT_LOAD) + continue; + + if (!phdr.p_filesz) + continue; + + errcode = load_section(iscache, image, name, phdr.p_offset, + phdr.p_filesz, phdr.p_vaddr + offset); + if (errcode < 0) { + fprintf(stderr, "%s: warning: %s: failed to create " + "section for phdr %u: %s.\n", prog, name, pidx, + pt_errstr(pt_errcode(errcode))); + continue; + } + + sections += 1; + + if (verbose) { + printf("%s:", name); + printf(" offset=0x%" PRIx64, phdr.p_offset); + printf(" size=0x%" PRIx64, phdr.p_filesz); + printf(" vaddr=0x%" PRIx64, phdr.p_vaddr); + printf(".\n"); + } + } + + if (!sections) + fprintf(stderr, + "%s: warning: %s: did not find any load sections.\n", + prog, name); + + return 0; +} + +int load_elf(struct pt_image_section_cache *iscache, struct pt_image *image, + const char *name, uint64_t base, const char *prog, int verbose) +{ + uint8_t e_ident[EI_NIDENT]; + FILE *file; + size_t count; + int errcode, idx; + + if (!image || !name) + return -pte_invalid; + + file = fopen(name, "rb"); + if (!file) { + fprintf(stderr, "%s: warning: failed to open %s: %s.\n", prog, + name, strerror(errno)); + return -pte_bad_config; + } + + count = fread(e_ident, sizeof(e_ident), 1, file); + if (count != 1) { + fprintf(stderr, + "%s: warning: %s failed to read file header: %s.\n", + prog, name, strerror(errno)); + + errcode = -pte_bad_config; + goto out; + } + + for (idx = 0; idx < SELFMAG; ++idx) { + if (e_ident[idx] != ELFMAG[idx]) { + fprintf(stderr, + "%s: warning: ignoring %s: not an ELF file.\n", + prog, name); + + errcode = -pte_bad_config; + goto out; + } + } + + switch (e_ident[EI_CLASS]) { + default: + fprintf(stderr, "%s: unsupported ELF class: %d\n", + prog, e_ident[EI_CLASS]); + errcode = -pte_bad_config; + break; + + case ELFCLASS32: + errcode = load_elf32(iscache, image, file, base, name, prog, + verbose); + break; + + case ELFCLASS64: + errcode = load_elf64(iscache, image, file, base, name, prog, + verbose); + break; + } + +out: + fclose(file); + return errcode; +} |
