libelf_xlate.c revision 260697
1292932Sdim/*- 2292932Sdim * Copyright (c) 2006,2008 Joseph Koshy 3353358Sdim * All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6292932Sdim * modification, are permitted provided that the following conditions 7292932Sdim * are met: 8292932Sdim * 1. Redistributions of source code must retain the above copyright 9292932Sdim * notice, this list of conditions and the following disclaimer. 10292932Sdim * 2. Redistributions in binary form must reproduce the above copyright 11292932Sdim * notice, this list of conditions and the following disclaimer in the 12292932Sdim * documentation and/or other materials provided with the distribution. 13353358Sdim * 14353358Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15353358Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16353358Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17292932Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18353358Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19353358Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20353358Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21353358Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22353358Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23353358Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24353358Sdim * SUCH DAMAGE. 25353358Sdim */ 26353358Sdim 27353358Sdim#include <sys/cdefs.h> 28353358Sdim 29292932Sdim#include <assert.h> 30353358Sdim#include <libelf.h> 31353358Sdim 32353358Sdim#include "_libelf.h" 33353358Sdim 34353358SdimELFTC_VCSID("$Id: libelf_xlate.c 2225 2011-11-26 18:55:54Z jkoshy $"); 35353358Sdim 36292932Sdim/* 37353358Sdim * Translate to/from the file representation of ELF objects. 38353358Sdim * 39353358Sdim * Translation could potentially involve the following 40353358Sdim * transformations: 41314564Sdim * 42294024Sdim * - an endianness conversion, 43353358Sdim * - a change of layout, as the file representation of ELF objects 44294024Sdim * can differ from their in-memory representation. 45353358Sdim * - a change in representation due to a layout version change. 46341825Sdim */ 47353358Sdim 48353358SdimElf_Data * 49353358Sdim_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding, 50353358Sdim int elfclass, int direction) 51353358Sdim{ 52292932Sdim int byteswap; 53353358Sdim size_t cnt, dsz, fsz, msz; 54292932Sdim uintptr_t sb, se, db, de; 55292932Sdim 56292932Sdim if (encoding == ELFDATANONE) 57353358Sdim encoding = LIBELF_PRIVATE(byteorder); 58353358Sdim 59353358Sdim if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) || 60353358Sdim dst == NULL || src == NULL || dst == src) { 61353358Sdim LIBELF_SET_ERROR(ARGUMENT, 0); 62353358Sdim return (NULL); 63314564Sdim } 64 65 assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); 66 assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); 67 68 if (dst->d_version != src->d_version) { 69 LIBELF_SET_ERROR(UNIMPL, 0); 70 return (NULL); 71 } 72 73 if (src->d_buf == NULL || dst->d_buf == NULL) { 74 LIBELF_SET_ERROR(DATA, 0); 75 return (NULL); 76 } 77 78 if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) { 79 LIBELF_SET_ERROR(DATA, 0); 80 return (NULL); 81 } 82 83 if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) 84 (src->d_type, (size_t) 1, src->d_version)) == 0) 85 return (NULL); 86 87 msz = _libelf_msize(src->d_type, elfclass, src->d_version); 88 89 assert(msz > 0); 90 91 if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) { 92 LIBELF_SET_ERROR(DATA, 0); 93 return (NULL); 94 } 95 96 /* 97 * Determine the number of objects that need to be converted, and 98 * the space required for the converted objects in the destination 99 * buffer. 100 */ 101 if (direction == ELF_TOMEMORY) { 102 cnt = src->d_size / fsz; 103 dsz = cnt * msz; 104 } else { 105 cnt = src->d_size / msz; 106 dsz = cnt * fsz; 107 } 108 109 if (dst->d_size < dsz) { 110 LIBELF_SET_ERROR(DATA, 0); 111 return (NULL); 112 } 113 114 sb = (uintptr_t) src->d_buf; 115 se = sb + src->d_size; 116 db = (uintptr_t) dst->d_buf; 117 de = db + dst->d_size; 118 119 /* 120 * Check for overlapping buffers. Note that db == sb is 121 * allowed. 122 */ 123 if (db != sb && de > sb && se > db) { 124 LIBELF_SET_ERROR(DATA, 0); 125 return (NULL); 126 } 127 128 if ((direction == ELF_TOMEMORY ? db : sb) % 129 _libelf_malign(src->d_type, elfclass)) { 130 LIBELF_SET_ERROR(DATA, 0); 131 return (NULL); 132 } 133 134 dst->d_type = src->d_type; 135 dst->d_size = dsz; 136 137 byteswap = encoding != LIBELF_PRIVATE(byteorder); 138 139 if (src->d_size == 0 || 140 (db == sb && !byteswap && fsz == msz)) 141 return (dst); /* nothing more to do */ 142 143 if (!(_libelf_get_translator(src->d_type, direction, elfclass)) 144 (dst->d_buf, dsz, src->d_buf, cnt, byteswap)) { 145 LIBELF_SET_ERROR(DATA, 0); 146 return (NULL); 147 } 148 149 return (dst); 150} 151