libelf_xlate.c revision 4484
13804SN/A/*-
212776Snikos.nikoleris@arm.com * Copyright (c) 2006 Joseph Koshy
39235Sandreas.hansson@arm.com * All rights reserved.
49235Sandreas.hansson@arm.com *
59235Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
69235Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions
79235Sandreas.hansson@arm.com * are met:
89235Sandreas.hansson@arm.com * 1. Redistributions of source code must retain the above copyright
99235Sandreas.hansson@arm.com *    notice, this list of conditions and the following disclaimer.
109235Sandreas.hansson@arm.com * 2. Redistributions in binary form must reproduce the above copyright
119235Sandreas.hansson@arm.com *    notice, this list of conditions and the following disclaimer in the
129235Sandreas.hansson@arm.com *    documentation and/or other materials provided with the distribution.
139235Sandreas.hansson@arm.com *
143804SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153804SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163804SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173804SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183804SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193804SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203804SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213804SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223804SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233804SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243804SN/A * SUCH DAMAGE.
253804SN/A */
263804SN/A
273804SN/A#include <assert.h>
283804SN/A
293804SN/A#include "libelf.h"
303804SN/A#include "_libelf.h"
313804SN/A
323804SN/A/*
333804SN/A * Translate to/from the file representation of ELF objects.
343804SN/A *
353804SN/A * Translation could potentially involve the following
363804SN/A * transformations:
373804SN/A *
383804SN/A * - an endianness conversion,
393804SN/A * - a change of layout, as the file representation of ELF objects
403804SN/A *   can differ from their in-memory representation.
419235Sandreas.hansson@arm.com * - a change in representation due to a layout version change.
423804SN/A */
433804SN/A
449235Sandreas.hansson@arm.comElf_Data *
459235Sandreas.hansson@arm.com_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
463804SN/A    int elfclass, int direction)
478229SN/A{
488902SN/A        size_t cnt, dsz, fsz, msz;
498229SN/A        uintptr_t sb, se, db, de;
509235Sandreas.hansson@arm.com
513804SN/A        if (encoding == ELFDATANONE)
528918SN/A                encoding = LIBELF_PRIVATE(byteorder);
539235Sandreas.hansson@arm.com
549235Sandreas.hansson@arm.com        if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) ||
559235Sandreas.hansson@arm.com            dst == NULL || src == NULL || dst == src)	{
568918SN/A                LIBELF_SET_ERROR(ARGUMENT, 0);
5712777Sgabeblack@google.com                return (NULL);
589235Sandreas.hansson@arm.com        }
593804SN/A
603804SN/A        assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
619235Sandreas.hansson@arm.com        assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
623804SN/A
633804SN/A        if (dst->d_version != src->d_version) {
643804SN/A                LIBELF_SET_ERROR(UNIMPL, 0);
658918SN/A                return (NULL);
663804SN/A        }
6712776Snikos.nikoleris@arm.com
6812776Snikos.nikoleris@arm.com        if  (src->d_buf == NULL || dst->d_buf == NULL ||
6912776Snikos.nikoleris@arm.com            src->d_size == 0) {
7012776Snikos.nikoleris@arm.com                LIBELF_SET_ERROR(DATA, 0);
7112776Snikos.nikoleris@arm.com                return (NULL);
7212776Snikos.nikoleris@arm.com        }
7312776Snikos.nikoleris@arm.com
7412776Snikos.nikoleris@arm.com        if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) {
7512776Snikos.nikoleris@arm.com                LIBELF_SET_ERROR(DATA, 0);
7612776Snikos.nikoleris@arm.com                return (NULL);
778918SN/A        }
7812776Snikos.nikoleris@arm.com
798918SN/A        if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)(src->d_type,
8012776Snikos.nikoleris@arm.com                 (size_t) 1, src->d_version)) == 0)
813804SN/A                return (NULL);
823804SN/A
8312776Snikos.nikoleris@arm.com        msz = _libelf_msize(src->d_type, elfclass, src->d_version);
8412776Snikos.nikoleris@arm.com
8512776Snikos.nikoleris@arm.com        assert(msz > 0);
8612776Snikos.nikoleris@arm.com
8712776Snikos.nikoleris@arm.com        if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) {
8812776Snikos.nikoleris@arm.com                LIBELF_SET_ERROR(DATA, 0);
8912776Snikos.nikoleris@arm.com                return (NULL);
9012776Snikos.nikoleris@arm.com        }
9112776Snikos.nikoleris@arm.com
9212776Snikos.nikoleris@arm.com        /*
938918SN/A         * Determine the number of objects that need to be converted, and
9412776Snikos.nikoleris@arm.com         * the space required for the converted objects in the destination
958918SN/A         * buffer.
9612776Snikos.nikoleris@arm.com         */
978918SN/A        if (direction == ELF_TOMEMORY) {
988918SN/A                cnt = src->d_size / fsz;
9912776Snikos.nikoleris@arm.com                dsz = cnt * msz;
10012776Snikos.nikoleris@arm.com        } else {
10112776Snikos.nikoleris@arm.com                cnt = src->d_size / msz;
10212776Snikos.nikoleris@arm.com                dsz = cnt * fsz;
10312776Snikos.nikoleris@arm.com        }
10412776Snikos.nikoleris@arm.com
10512776Snikos.nikoleris@arm.com        if (dst->d_size  <  dsz) {
10612776Snikos.nikoleris@arm.com                LIBELF_SET_ERROR(DATA, 0);
10712776Snikos.nikoleris@arm.com                return (NULL);
10812776Snikos.nikoleris@arm.com        }
10912776Snikos.nikoleris@arm.com
11012776Snikos.nikoleris@arm.com        sb = (uintptr_t) src->d_buf;
1115609SN/A        se = sb + src->d_size;
11212776Snikos.nikoleris@arm.com        db = (uintptr_t) dst->d_buf;
1135609SN/A        de = db + dst->d_size;
1145609SN/A
1159409Sandreas.hansson@arm.com        /*
1169235Sandreas.hansson@arm.com         * Check for overlapping buffers.  Note that db == sb is
1173804SN/A         * allowed.
11812776Snikos.nikoleris@arm.com         */
1193804SN/A        if (db != sb && de > sb && se > db) {
1203804SN/A                LIBELF_SET_ERROR(DATA, 0);
1218902SN/A                return (NULL);
1223804SN/A        }
1233804SN/A
1245608SN/A        if ((direction == ELF_TOMEMORY ? db : sb) %
1255608SN/A            _libelf_malign(src->d_type, elfclass)) {
1263804SN/A                LIBELF_SET_ERROR(DATA, 0);
12712777Sgabeblack@google.com                return (NULL);
1283804SN/A        }
1293804SN/A
1303804SN/A        dst->d_type = src->d_type;
1315608SN/A        dst->d_size = dsz;
1325608SN/A
1333804SN/A        if (db == sb && encoding == LIBELF_PRIVATE(byteorder) &&
13412777Sgabeblack@google.com            fsz == msz)
13512777Sgabeblack@google.com                return (dst);	/* nothing more to do */
13612777Sgabeblack@google.com
1373804SN/A        (_libelf_get_translator(src->d_type, direction, elfclass))(dst->d_buf,
1383804SN/A            src->d_buf, cnt, encoding != LIBELF_PRIVATE(byteorder));
1393804SN/A
1405608SN/A        return (dst);
1415608SN/A}
1423804SN/A