240 lines
5.8 KiB
C
Executable File
240 lines
5.8 KiB
C
Executable File
/*
|
|
cook.c - read and translate ELF files.
|
|
Copyright (C) 1995 Michael Riepe <riepe@ifwsn4.ifw.uni-hannover.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <private.h>
|
|
|
|
const Elf_Scn _elf_scn_init = INIT_SCN;
|
|
const Scn_Data _elf_data_init = INIT_DATA;
|
|
|
|
const Elf_Type _elf_scn_types[SHT_NUM] = {
|
|
/* SHT_NULL */ ELF_T_BYTE,
|
|
/* SHT_PROGBITS */ ELF_T_BYTE,
|
|
/* SHT_SYMTAB */ ELF_T_SYM,
|
|
/* SHT_STRTAB */ ELF_T_BYTE,
|
|
/* SHT_RELA */ ELF_T_RELA,
|
|
/* SHT_HASH */ ELF_T_WORD,
|
|
/* SHT_DYNAMIC */ ELF_T_DYN,
|
|
/* SHT_NOTE */ ELF_T_BYTE,
|
|
/* SHT_NOBITS */ ELF_T_BYTE,
|
|
/* SHT_REL */ ELF_T_REL,
|
|
/* SHT_SHLIB */ ELF_T_BYTE,
|
|
/* SHT_DYNSYM */ ELF_T_SYM
|
|
};
|
|
|
|
#define truncerr(t) ((t)==ELF_T_EHDR?ERROR_TRUNC_EHDR: \
|
|
((t)==ELF_T_PHDR?ERROR_TRUNC_PHDR: \
|
|
((t)==ELF_T_SHDR?ERROR_TRUNC_SHDR: \
|
|
ERROR_INTERNAL)))
|
|
#define memerr(t) ((t)==ELF_T_EHDR?ERROR_MEM_EHDR: \
|
|
((t)==ELF_T_PHDR?ERROR_MEM_PHDR: \
|
|
((t)==ELF_T_SHDR?ERROR_MEM_SHDR: \
|
|
ERROR_INTERNAL)))
|
|
|
|
static char*
|
|
_elf32_item(Elf *elf, Elf_Type type, unsigned n, size_t off, int *flag) {
|
|
Elf_Data src, dst;
|
|
|
|
*flag = 0;
|
|
elf_assert(n);
|
|
elf_assert(valid_type(type));
|
|
if (off < 0 || off > elf->e_size) {
|
|
seterr(ERROR_OUTSIDE);
|
|
return NULL;
|
|
}
|
|
|
|
src.d_type = type;
|
|
src.d_version = elf->e_version;
|
|
src.d_size = n * _fsize32(src.d_version, type);
|
|
elf_assert(src.d_size);
|
|
if (off + src.d_size > elf->e_size) {
|
|
seterr(truncerr(type));
|
|
return NULL;
|
|
}
|
|
|
|
dst.d_version = _elf_version;
|
|
dst.d_size = n * _msize32(dst.d_version, type);
|
|
elf_assert(dst.d_size);
|
|
|
|
elf_assert(elf->e_data);
|
|
if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) {
|
|
dst.d_buf = elf->e_data + off;
|
|
}
|
|
else if (!(dst.d_buf = malloc(dst.d_size))) {
|
|
seterr(memerr(type));
|
|
return NULL;
|
|
}
|
|
else {
|
|
*flag |= 1;
|
|
}
|
|
|
|
if (elf->e_rawdata) {
|
|
src.d_buf = elf->e_rawdata + off;
|
|
}
|
|
else {
|
|
if (src.d_size <= dst.d_size) {
|
|
src.d_buf = dst.d_buf;
|
|
}
|
|
else if (!(src.d_buf = malloc(src.d_size))) {
|
|
seterr(ERROR_IO_2BIG);
|
|
goto fail;
|
|
}
|
|
else {
|
|
*flag |= 2;
|
|
}
|
|
|
|
if (!_elf_read(elf, src.d_buf, off, src.d_size)) {
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
if (elf32_xlatetom(&dst, &src, elf->e_encoding)) {
|
|
if (*flag & 2) {
|
|
free(src.d_buf);
|
|
}
|
|
if (!(*flag &= 1)) {
|
|
elf->e_cooked = 1;
|
|
}
|
|
return (char*)dst.d_buf;
|
|
}
|
|
|
|
fail:
|
|
if (*flag & 2) {
|
|
free(src.d_buf);
|
|
}
|
|
if (*flag & 1) {
|
|
free(dst.d_buf);
|
|
}
|
|
*flag = 0;
|
|
return NULL;
|
|
}
|
|
|
|
#undef truncerr
|
|
#undef memerr
|
|
|
|
static int
|
|
_elf32_cook(Elf *elf) {
|
|
Elf_Scn *head, *scn;
|
|
Elf32_Ehdr *ehdr;
|
|
Elf32_Shdr *shdr;
|
|
Scn_Data *data;
|
|
Scn_Data *sd;
|
|
unsigned i;
|
|
int flag;
|
|
|
|
elf->e_ehdr = _elf32_item(elf, ELF_T_EHDR, 1, 0, &flag);
|
|
if (!(ehdr = (Elf32_Ehdr*)elf->e_ehdr)) {
|
|
return 0;
|
|
}
|
|
if (flag) {
|
|
elf->e_free_ehdr = 1;
|
|
}
|
|
if (ehdr->e_phnum && ehdr->e_phoff) {
|
|
elf->e_phdr = _elf32_item(elf, ELF_T_PHDR, ehdr->e_phnum, ehdr->e_phoff, &flag);
|
|
if (!elf->e_phdr) {
|
|
return 0;
|
|
}
|
|
if (flag) {
|
|
elf->e_free_phdr = 1;
|
|
}
|
|
elf->e_phnum = ehdr->e_phnum;
|
|
}
|
|
if (ehdr->e_shnum && ehdr->e_shoff) {
|
|
unsigned tmp = _elf_version;
|
|
|
|
elf_assert(_msize32(_elf_version, ELF_T_SHDR) <= sizeof(*shdr));
|
|
_elf_version = EV_CURRENT;
|
|
elf_assert(_msize32(_elf_version, ELF_T_SHDR) == sizeof(*shdr));
|
|
elf->e_shdr = _elf32_item(elf, ELF_T_SHDR, ehdr->e_shnum, ehdr->e_shoff, &flag);
|
|
_elf_version = tmp;
|
|
if (!elf->e_shdr) {
|
|
return 0;
|
|
}
|
|
if (flag) {
|
|
elf->e_free_shdr = 1;
|
|
}
|
|
head = (Elf_Scn*)malloc(ehdr->e_shnum * (sizeof(*head) + sizeof(*data)));
|
|
if (!head) {
|
|
seterr(ERROR_MEM_SCN);
|
|
return 0;
|
|
}
|
|
data = (Scn_Data*)(head + ehdr->e_shnum);
|
|
for (scn = NULL, i = ehdr->e_shnum; i-- > 0; ) {
|
|
head[i] = _elf_scn_init;
|
|
head[i].s_link = scn;
|
|
if (!scn) {
|
|
elf->e_scn_n = head + i;
|
|
}
|
|
shdr = (Elf32_Shdr*)elf->e_shdr + i;
|
|
scn = head + i;
|
|
sd = data + i;
|
|
|
|
scn->s_elf = elf;
|
|
scn->s_shdr = (char*)shdr;
|
|
scn->s_index = i;
|
|
scn->s_data_1 = sd;
|
|
scn->s_data_n = sd;
|
|
scn->s_type = shdr->sh_type;
|
|
scn->s_size = shdr->sh_size;
|
|
scn->s_offset = shdr->sh_offset;
|
|
|
|
*sd = _elf_data_init;
|
|
sd->sd_scn = scn;
|
|
|
|
if (valid_scntype(shdr->sh_type)) {
|
|
sd->sd_data.d_type = _elf_scn_types[shdr->sh_type];
|
|
}
|
|
else {
|
|
sd->sd_data.d_type = ELF_T_BYTE;
|
|
}
|
|
sd->sd_data.d_size = shdr->sh_size;
|
|
sd->sd_data.d_align = shdr->sh_addralign;
|
|
sd->sd_data.d_version = _elf_version;
|
|
}
|
|
elf->e_scn_1 = head;
|
|
head->s_freeme = 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
_elf_cook(Elf *elf) {
|
|
elf_assert(_elf_scn_init.s_magic == SCN_MAGIC);
|
|
elf_assert(_elf_data_init.sd_magic == DATA_MAGIC);
|
|
elf_assert(elf);
|
|
elf_assert(elf->e_magic == ELF_MAGIC);
|
|
elf_assert(elf->e_kind == ELF_K_ELF);
|
|
elf_assert(!elf->e_ehdr);
|
|
if (!valid_version(elf->e_version)) {
|
|
seterr(ERROR_UNKNOWN_VERSION);
|
|
}
|
|
else if (!valid_encoding(elf->e_encoding)) {
|
|
seterr(ERROR_UNKNOWN_ENCODING);
|
|
}
|
|
else if (elf->e_class == ELFCLASS32) {
|
|
return _elf32_cook(elf);
|
|
}
|
|
else if (valid_class(elf->e_class)) {
|
|
seterr(ERROR_UNIMPLEMENTED);
|
|
}
|
|
else {
|
|
seterr(ERROR_UNKNOWN_CLASS);
|
|
}
|
|
return 0;
|
|
}
|