|
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 |
}
|