1164190Sjkoshy/*- 2164190Sjkoshy * Copyright (c) 2006 Joseph Koshy 3164190Sjkoshy * All rights reserved. 4164190Sjkoshy * 5164190Sjkoshy * Redistribution and use in source and binary forms, with or without 6164190Sjkoshy * modification, are permitted provided that the following conditions 7164190Sjkoshy * are met: 8164190Sjkoshy * 1. Redistributions of source code must retain the above copyright 9164190Sjkoshy * notice, this list of conditions and the following disclaimer. 10164190Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11164190Sjkoshy * notice, this list of conditions and the following disclaimer in the 12164190Sjkoshy * documentation and/or other materials provided with the distribution. 13164190Sjkoshy * 14164190Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15164190Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16164190Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17164190Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18164190Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19164190Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20164190Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21164190Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22164190Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23164190Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24164190Sjkoshy * SUCH DAMAGE. 25164190Sjkoshy */ 26164190Sjkoshy 27164190Sjkoshy#include <sys/cdefs.h> 28164190Sjkoshy__FBSDID("$FreeBSD$"); 29164190Sjkoshy 30164190Sjkoshy#include <sys/limits.h> 31164190Sjkoshy 32164190Sjkoshy#include <assert.h> 33164190Sjkoshy#include <gelf.h> 34164190Sjkoshy 35164190Sjkoshy#include "_libelf.h" 36164190Sjkoshy 37164190SjkoshyGElf_Rel * 38164190Sjkoshygelf_getrel(Elf_Data *d, int ndx, GElf_Rel *dst) 39164190Sjkoshy{ 40164190Sjkoshy int ec; 41164190Sjkoshy Elf *e; 42164190Sjkoshy Elf_Scn *scn; 43164190Sjkoshy Elf32_Rel *rel32; 44164190Sjkoshy Elf64_Rel *rel64; 45164190Sjkoshy size_t msz; 46164190Sjkoshy uint32_t sh_type; 47164190Sjkoshy 48164190Sjkoshy if (d == NULL || ndx < 0 || dst == NULL || 49164190Sjkoshy (scn = d->d_scn) == NULL || 50164190Sjkoshy (e = scn->s_elf) == NULL) { 51164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 52164190Sjkoshy return (NULL); 53164190Sjkoshy } 54164190Sjkoshy 55164190Sjkoshy ec = e->e_class; 56164190Sjkoshy assert(ec == ELFCLASS32 || ec == ELFCLASS64); 57164190Sjkoshy 58164190Sjkoshy if (ec == ELFCLASS32) 59164190Sjkoshy sh_type = scn->s_shdr.s_shdr32.sh_type; 60164190Sjkoshy else 61164190Sjkoshy sh_type = scn->s_shdr.s_shdr64.sh_type; 62164190Sjkoshy 63164190Sjkoshy if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { 64164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 65164190Sjkoshy return (NULL); 66164190Sjkoshy } 67164190Sjkoshy 68164190Sjkoshy msz = _libelf_msize(ELF_T_REL, ec, e->e_version); 69164190Sjkoshy 70164190Sjkoshy assert(msz > 0); 71164190Sjkoshy 72164190Sjkoshy if (msz * ndx >= d->d_size) { 73164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 74164190Sjkoshy return (NULL); 75164190Sjkoshy } 76164190Sjkoshy 77164190Sjkoshy if (ec == ELFCLASS32) { 78164190Sjkoshy rel32 = (Elf32_Rel *) d->d_buf + ndx; 79164190Sjkoshy 80164190Sjkoshy dst->r_offset = (Elf64_Addr) rel32->r_offset; 81176727Sjkoshy dst->r_info = ELF64_R_INFO( 82176727Sjkoshy (Elf64_Xword) ELF32_R_SYM(rel32->r_info), 83176727Sjkoshy ELF32_R_TYPE(rel32->r_info)); 84164190Sjkoshy 85164190Sjkoshy } else { 86164190Sjkoshy 87164190Sjkoshy rel64 = (Elf64_Rel *) d->d_buf + ndx; 88164190Sjkoshy 89164190Sjkoshy *dst = *rel64; 90164190Sjkoshy } 91164190Sjkoshy 92164190Sjkoshy return (dst); 93164190Sjkoshy} 94164190Sjkoshy 95164190Sjkoshyint 96164190Sjkoshygelf_update_rel(Elf_Data *d, int ndx, GElf_Rel *dr) 97164190Sjkoshy{ 98164190Sjkoshy int ec; 99164190Sjkoshy Elf *e; 100164190Sjkoshy Elf_Scn *scn; 101164190Sjkoshy Elf32_Rel *rel32; 102164190Sjkoshy Elf64_Rel *rel64; 103164190Sjkoshy size_t msz; 104164190Sjkoshy uint32_t sh_type; 105164190Sjkoshy 106164190Sjkoshy if (d == NULL || ndx < 0 || dr == NULL || 107164190Sjkoshy (scn = d->d_scn) == NULL || 108164190Sjkoshy (e = scn->s_elf) == NULL) { 109164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 110164190Sjkoshy return (0); 111164190Sjkoshy } 112164190Sjkoshy 113164190Sjkoshy ec = e->e_class; 114164190Sjkoshy assert(ec == ELFCLASS32 || ec == ELFCLASS64); 115164190Sjkoshy 116164190Sjkoshy if (ec == ELFCLASS32) 117164190Sjkoshy sh_type = scn->s_shdr.s_shdr32.sh_type; 118164190Sjkoshy else 119164190Sjkoshy sh_type = scn->s_shdr.s_shdr64.sh_type; 120164190Sjkoshy 121164190Sjkoshy if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { 122164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 123164190Sjkoshy return (0); 124164190Sjkoshy } 125164190Sjkoshy 126164190Sjkoshy msz = _libelf_msize(ELF_T_REL, ec, e->e_version); 127164190Sjkoshy assert(msz > 0); 128164190Sjkoshy 129164190Sjkoshy if (msz * ndx >= d->d_size) { 130164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 131164190Sjkoshy return (0); 132164190Sjkoshy } 133164190Sjkoshy 134164190Sjkoshy if (ec == ELFCLASS32) { 135164190Sjkoshy rel32 = (Elf32_Rel *) d->d_buf + ndx; 136164190Sjkoshy 137164190Sjkoshy LIBELF_COPY_U32(rel32, dr, r_offset); 138176727Sjkoshy 139176727Sjkoshy if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || 140176727Sjkoshy ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { 141176727Sjkoshy LIBELF_SET_ERROR(RANGE, 0); 142176727Sjkoshy return (0); 143176727Sjkoshy } 144176727Sjkoshy rel32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), 145176727Sjkoshy ELF64_R_TYPE(dr->r_info)); 146164190Sjkoshy } else { 147164190Sjkoshy rel64 = (Elf64_Rel *) d->d_buf + ndx; 148164190Sjkoshy 149164190Sjkoshy *rel64 = *dr; 150164190Sjkoshy } 151164190Sjkoshy 152164190Sjkoshy return (1); 153164190Sjkoshy} 154