Blame ptxed/src/load_elf.c

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