diff -r 1af5c1be89f8 -r 92d87f2e53c2 tools/elf4rom/libs/libelf-0.8.10/lib/gelftrans.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/elf4rom/libs/libelf-0.8.10/lib/gelftrans.c Fri Jan 15 09:07:44 2010 +0000 @@ -0,0 +1,407 @@ +/* +gelftrans.c - gelf_* translation functions. +Copyright (C) 2000 - 2001 Michael Riepe + +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 + +#if __LIBELF64 + +#ifndef lint +static const char rcsid[] = "@(#) $Id: gelftrans.c,v 1.9 2005/05/21 15:39:23 michael Exp $"; +#endif /* lint */ + +#define check_and_copy(type, d, s, name, eret) \ + do { \ + if (sizeof((d)->name) < sizeof((s)->name) \ + && (type)(s)->name != (s)->name) { \ + seterr(ERROR_BADVALUE); \ + return (eret); \ + } \ + (d)->name = (type)(s)->name; \ + } while (0) + +/* + * These macros are missing on some Linux systems + */ +#if !defined(ELF32_R_SYM) || !defined(ELF32_R_TYPE) || !defined(ELF32_R_INFO) +# undef ELF32_R_SYM +# undef ELF32_R_TYPE +# undef ELF32_R_INFO +# define ELF32_R_SYM(i) ((i)>>8) +# define ELF32_R_TYPE(i) ((unsigned char)(i)) +# define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) +#endif /* !defined(...) */ + +#if !defined(ELF64_R_SYM) || !defined(ELF64_R_TYPE) || !defined(ELF64_R_INFO) +# undef ELF64_R_SYM +# undef ELF64_R_TYPE +# undef ELF64_R_INFO +# define ELF64_R_SYM(i) ((i)>>32) +# define ELF64_R_TYPE(i) ((i)&0xffffffffL) +# define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+((t)&0xffffffffL)) +#endif /* !defined(...) */ + +static char* +get_addr_and_class(const Elf_Data *data, int ndx, Elf_Type type, unsigned *cls) { + Scn_Data *sd = (Scn_Data*)data; + Elf_Scn *scn; + Elf *elf; + size_t n; + + if (!sd) { + return NULL; + } + elf_assert(sd->sd_magic == DATA_MAGIC); + scn = sd->sd_scn; + elf_assert(scn); + elf_assert(scn->s_magic == SCN_MAGIC); + elf = scn->s_elf; + elf_assert(elf); + elf_assert(elf->e_magic == ELF_MAGIC); + if (elf->e_kind != ELF_K_ELF) { + seterr(ERROR_NOTELF); + return NULL; + } + if (!valid_class(elf->e_class)) { + seterr(ERROR_UNKNOWN_CLASS); + return NULL; + } + if (data->d_type != type) { + seterr(ERROR_BADTYPE); + return NULL; + } + n = _msize(elf->e_class, data->d_version, type); + if (n == 0) { + seterr(ERROR_UNIMPLEMENTED); + return NULL; + } + if (ndx < 0 || data->d_size < (ndx + 1) * n) { + seterr(ERROR_BADINDEX); + return NULL; + } + if (!data->d_buf) { + seterr(ERROR_NULLBUF); + return NULL; + } + if (cls) { + *cls = elf->e_class; + } + return (char*)data->d_buf + n * ndx; +} + +GElf_Sym* +gelf_getsym(Elf_Data *src, int ndx, GElf_Sym *dst) { + GElf_Sym buf; + unsigned cls; + char *tmp; + + if (!dst) { + dst = &buf; + } + tmp = get_addr_and_class(src, ndx, ELF_T_SYM, &cls); + if (!tmp) { + return NULL; + } + if (cls == ELFCLASS64) { + *dst = *(Elf64_Sym*)tmp; + } + else if (cls == ELFCLASS32) { + Elf32_Sym *src = (Elf32_Sym*)tmp; + + check_and_copy(GElf_Word, dst, src, st_name, NULL); + check_and_copy(unsigned char, dst, src, st_info, NULL); + check_and_copy(unsigned char, dst, src, st_other, NULL); + check_and_copy(GElf_Half, dst, src, st_shndx, NULL); + check_and_copy(GElf_Addr, dst, src, st_value, NULL); + check_and_copy(GElf_Xword, dst, src, st_size, NULL); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return NULL; + } + if (dst == &buf) { + dst = (GElf_Sym*)malloc(sizeof(GElf_Sym)); + if (!dst) { + seterr(ERROR_MEM_SYM); + return NULL; + } + *dst = buf; + } + return dst; +} + +int +gelf_update_sym(Elf_Data *dst, int ndx, GElf_Sym *src) { + unsigned cls; + char *tmp; + + tmp = get_addr_and_class(dst, ndx, ELF_T_SYM, &cls); + if (!tmp) { + return 0; + } + if (cls == ELFCLASS64) { + *(Elf64_Sym*)tmp = *src; + } + else if (cls == ELFCLASS32) { + Elf32_Sym *dst = (Elf32_Sym*)tmp; + + check_and_copy(Elf32_Word, dst, src, st_name, 0); + check_and_copy(Elf32_Addr, dst, src, st_value, 0); + check_and_copy(Elf32_Word, dst, src, st_size, 0); + check_and_copy(unsigned char, dst, src, st_info, 0); + check_and_copy(unsigned char, dst, src, st_other, 0); + check_and_copy(Elf32_Half, dst, src, st_shndx, 0); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return 0; + } + return 1; +} + +GElf_Dyn* +gelf_getdyn(Elf_Data *src, int ndx, GElf_Dyn *dst) { + GElf_Dyn buf; + unsigned cls; + char *tmp; + + if (!dst) { + dst = &buf; + } + tmp = get_addr_and_class(src, ndx, ELF_T_DYN, &cls); + if (!tmp) { + return NULL; + } + if (cls == ELFCLASS64) { + *dst = *(Elf64_Dyn*)tmp; + } + else if (cls == ELFCLASS32) { + Elf32_Dyn *src = (Elf32_Dyn*)tmp; + + check_and_copy(GElf_Sxword, dst, src, d_tag, NULL); + check_and_copy(GElf_Xword, dst, src, d_un.d_val, NULL); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return NULL; + } + if (dst == &buf) { + dst = (GElf_Dyn*)malloc(sizeof(GElf_Dyn)); + if (!dst) { + seterr(ERROR_MEM_DYN); + return NULL; + } + *dst = buf; + } + return dst; +} + +int +gelf_update_dyn(Elf_Data *dst, int ndx, GElf_Dyn *src) { + unsigned cls; + char *tmp; + + tmp = get_addr_and_class(dst, ndx, ELF_T_DYN, &cls); + if (!tmp) { + return 0; + } + if (cls == ELFCLASS64) { + *(Elf64_Dyn*)tmp = *src; + } + else if (cls == ELFCLASS32) { + Elf32_Dyn *dst = (Elf32_Dyn*)tmp; + + check_and_copy(Elf32_Sword, dst, src, d_tag, 0); + check_and_copy(Elf32_Word, dst, src, d_un.d_val, 0); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return 0; + } + return 1; +} + +GElf_Rela* +gelf_getrela(Elf_Data *src, int ndx, GElf_Rela *dst) { + GElf_Rela buf; + unsigned cls; + char *tmp; + + if (!dst) { + dst = &buf; + } + tmp = get_addr_and_class(src, ndx, ELF_T_RELA, &cls); + if (!tmp) { + return NULL; + } + if (cls == ELFCLASS64) { + *dst = *(Elf64_Rela*)tmp; + } + else if (cls == ELFCLASS32) { + Elf32_Rela *src = (Elf32_Rela*)tmp; + + check_and_copy(GElf_Addr, dst, src, r_offset, NULL); + dst->r_info = ELF64_R_INFO((Elf64_Xword)ELF32_R_SYM(src->r_info), + (Elf64_Xword)ELF32_R_TYPE(src->r_info)); + check_and_copy(GElf_Sxword, dst, src, r_addend, NULL); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return NULL; + } + if (dst == &buf) { + dst = (GElf_Rela*)malloc(sizeof(GElf_Rela)); + if (!dst) { + seterr(ERROR_MEM_RELA); + return NULL; + } + *dst = buf; + } + return dst; +} + +int +gelf_update_rela(Elf_Data *dst, int ndx, GElf_Rela *src) { + unsigned cls; + char *tmp; + + tmp = get_addr_and_class(dst, ndx, ELF_T_RELA, &cls); + if (!tmp) { + return 0; + } + if (cls == ELFCLASS64) { + *(Elf64_Rela*)tmp = *src; + } + else if (cls == ELFCLASS32) { + Elf32_Rela *dst = (Elf32_Rela*)tmp; + + check_and_copy(Elf32_Addr, dst, src, r_offset, 0); + if (ELF64_R_SYM(src->r_info) > 0xffffffUL + || ELF64_R_TYPE(src->r_info) > 0xffUL) { + seterr(ERROR_BADVALUE); + return 0; + } + dst->r_info = ELF32_R_INFO((Elf32_Word)ELF64_R_SYM(src->r_info), + (Elf32_Word)ELF64_R_TYPE(src->r_info)); + check_and_copy(Elf32_Sword, dst, src, r_addend, 0); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return 0; + } + return 1; +} + +GElf_Rel* +gelf_getrel(Elf_Data *src, int ndx, GElf_Rel *dst) { + GElf_Rel buf; + unsigned cls; + char *tmp; + + if (!dst) { + dst = &buf; + } + tmp = get_addr_and_class(src, ndx, ELF_T_REL, &cls); + if (!tmp) { + return NULL; + } + if (cls == ELFCLASS64) { + *dst = *(Elf64_Rel*)tmp; + } + else if (cls == ELFCLASS32) { + Elf32_Rel *src = (Elf32_Rel*)tmp; + + check_and_copy(GElf_Addr, dst, src, r_offset, NULL); + dst->r_info = ELF64_R_INFO((Elf64_Xword)ELF32_R_SYM(src->r_info), + (Elf64_Xword)ELF32_R_TYPE(src->r_info)); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return NULL; + } + if (dst == &buf) { + dst = (GElf_Rel*)malloc(sizeof(GElf_Rel)); + if (!dst) { + seterr(ERROR_MEM_REL); + return NULL; + } + *dst = buf; + } + return dst; +} + +int +gelf_update_rel(Elf_Data *dst, int ndx, GElf_Rel *src) { + unsigned cls; + char *tmp; + + tmp = get_addr_and_class(dst, ndx, ELF_T_REL, &cls); + if (!tmp) { + return 0; + } + if (cls == ELFCLASS64) { + *(Elf64_Rel*)tmp = *src; + } + else if (cls == ELFCLASS32) { + Elf32_Rel *dst = (Elf32_Rel*)tmp; + + check_and_copy(Elf32_Addr, dst, src, r_offset, 0); + if (ELF64_R_SYM(src->r_info) > 0xffffffUL + || ELF64_R_TYPE(src->r_info) > 0xffUL) { + seterr(ERROR_BADVALUE); + return 0; + } + dst->r_info = ELF32_R_INFO((Elf32_Word)ELF64_R_SYM(src->r_info), + (Elf32_Word)ELF64_R_TYPE(src->r_info)); + } + else { + seterr(ERROR_UNIMPLEMENTED); + return 0; + } + return 1; +} + +#if 0 + +GElf_Syminfo* +gelf_getsyminfo(Elf_Data *src, int ndx, GElf_Syminfo *dst) { + seterr(ERROR_UNIMPLEMENTED); + return NULL; +} + +int +gelf_update_syminfo(Elf_Data *dst, int ndx, GElf_Syminfo *src) { + seterr(ERROR_UNIMPLEMENTED); + return 0; +} + +GElf_Move* +gelf_getmove(Elf_Data *src, int ndx, GElf_Move *src) { + seterr(ERROR_UNIMPLEMENTED); + return NULL; +} + +int +gelf_update_move(Elf_Data *dst, int ndx, GElf_Move *src) { + seterr(ERROR_UNIMPLEMENTED); + return 0; +} + +#endif + +#endif /* __LIBELF64 */