diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-09-04 18:09:07 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-09-04 18:09:07 +0400 |
commit | ea8b1f90d46279d7814a0c7f6b6742d3fab034f7 (patch) | |
tree | d626f0ab0d0016423d9ac76473ec928c231b91a5 /lib/gelftrans.c | |
download | libelf-upstream.tar.gz |
Imported Upstream version 0.8.13upstream
Diffstat (limited to 'lib/gelftrans.c')
-rw-r--r-- | lib/gelftrans.c | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/lib/gelftrans.c b/lib/gelftrans.c new file mode 100644 index 0000000..dcd0cdd --- /dev/null +++ b/lib/gelftrans.c @@ -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include <private.h> + +#if __LIBELF64 + +#ifndef lint +static const char rcsid[] = "@(#) $Id: gelftrans.c,v 1.10 2008/05/23 08:15:34 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 */ |