1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2006,2008 Joseph Koshy
3260684Skaiw * All rights reserved.
4260684Skaiw *
5260684Skaiw * Redistribution and use in source and binary forms, with or without
6260684Skaiw * modification, are permitted provided that the following conditions
7260684Skaiw * are met:
8260684Skaiw * 1. Redistributions of source code must retain the above copyright
9260684Skaiw *    notice, this list of conditions and the following disclaimer.
10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer in the
12260684Skaiw *    documentation and/or other materials provided with the distribution.
13260684Skaiw *
14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24260684Skaiw * SUCH DAMAGE.
25260684Skaiw */
26260684Skaiw
27260684Skaiw#include <assert.h>
28260684Skaiw#include <libelf.h>
29260684Skaiw
30260684Skaiw#include "_libelf.h"
31260684Skaiw
32367466SdimELFTC_VCSID("$Id: libelf_xlate.c 3732 2019-04-22 11:08:38Z jkoshy $");
33260684Skaiw
34260684Skaiw/*
35260684Skaiw * Translate to/from the file representation of ELF objects.
36260684Skaiw *
37260684Skaiw * Translation could potentially involve the following
38260684Skaiw * transformations:
39260684Skaiw *
40260684Skaiw * - an endianness conversion,
41260684Skaiw * - a change of layout, as the file representation of ELF objects
42260684Skaiw *   can differ from their in-memory representation.
43260684Skaiw * - a change in representation due to a layout version change.
44260684Skaiw */
45260684Skaiw
46260684SkaiwElf_Data *
47260684Skaiw_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
48367466Sdim    int elfclass, int elfmachine, int direction)
49260684Skaiw{
50260684Skaiw	int byteswap;
51260684Skaiw	size_t cnt, dsz, fsz, msz;
52260684Skaiw	uintptr_t sb, se, db, de;
53367466Sdim	_libelf_translator_function *xlator;
54260684Skaiw
55260684Skaiw	if (encoding == ELFDATANONE)
56260684Skaiw		encoding = LIBELF_PRIVATE(byteorder);
57260684Skaiw
58260684Skaiw	if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) ||
59260684Skaiw	    dst == NULL || src == NULL || dst == src)	{
60260684Skaiw		LIBELF_SET_ERROR(ARGUMENT, 0);
61260684Skaiw		return (NULL);
62260684Skaiw	}
63260684Skaiw
64260684Skaiw	assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
65260684Skaiw	assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
66260684Skaiw
67260684Skaiw	if (dst->d_version != src->d_version) {
68260684Skaiw		LIBELF_SET_ERROR(UNIMPL, 0);
69260684Skaiw		return (NULL);
70260684Skaiw	}
71260684Skaiw
72260684Skaiw	if  (src->d_buf == NULL || dst->d_buf == NULL) {
73260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
74260684Skaiw		return (NULL);
75260684Skaiw	}
76260684Skaiw
77260684Skaiw	if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) {
78260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
79260684Skaiw		return (NULL);
80260684Skaiw	}
81260684Skaiw
82260684Skaiw	if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
83260684Skaiw	    (src->d_type, (size_t) 1, src->d_version)) == 0)
84260684Skaiw		return (NULL);
85260684Skaiw
86367466Sdim	if ((msz = _libelf_msize(src->d_type, elfclass, src->d_version)) == 0)
87367466Sdim		return (NULL);
88260684Skaiw
89260684Skaiw	if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) {
90260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
91260684Skaiw		return (NULL);
92260684Skaiw	}
93260684Skaiw
94260684Skaiw	/*
95260684Skaiw	 * Determine the number of objects that need to be converted, and
96260684Skaiw	 * the space required for the converted objects in the destination
97260684Skaiw	 * buffer.
98260684Skaiw	 */
99260684Skaiw	if (direction == ELF_TOMEMORY) {
100276371Semaste		cnt = (size_t) src->d_size / fsz;
101260684Skaiw		dsz = cnt * msz;
102260684Skaiw	} else {
103276371Semaste		cnt = (size_t) src->d_size / msz;
104260684Skaiw		dsz = cnt * fsz;
105260684Skaiw	}
106260684Skaiw
107260684Skaiw	if (dst->d_size  <  dsz) {
108260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
109260684Skaiw		return (NULL);
110260684Skaiw	}
111260684Skaiw
112260684Skaiw	sb = (uintptr_t) src->d_buf;
113276371Semaste	se = sb + (size_t) src->d_size;
114260684Skaiw	db = (uintptr_t) dst->d_buf;
115276371Semaste	de = db + (size_t) dst->d_size;
116260684Skaiw
117260684Skaiw	/*
118260684Skaiw	 * Check for overlapping buffers.  Note that db == sb is
119260684Skaiw	 * allowed.
120260684Skaiw	 */
121260684Skaiw	if (db != sb && de > sb && se > db) {
122260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
123260684Skaiw		return (NULL);
124260684Skaiw	}
125260684Skaiw
126260684Skaiw	if ((direction == ELF_TOMEMORY ? db : sb) %
127260684Skaiw	    _libelf_malign(src->d_type, elfclass)) {
128260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
129260684Skaiw		return (NULL);
130260684Skaiw	}
131260684Skaiw
132260684Skaiw	dst->d_type = src->d_type;
133260684Skaiw	dst->d_size = dsz;
134260684Skaiw
135260684Skaiw	byteswap = encoding != LIBELF_PRIVATE(byteorder);
136260684Skaiw
137260684Skaiw	if (src->d_size == 0 ||
138260684Skaiw	    (db == sb && !byteswap && fsz == msz))
139260684Skaiw		return (dst);	/* nothing more to do */
140260684Skaiw
141367466Sdim	xlator = _libelf_get_translator(src->d_type, direction, elfclass,
142367466Sdim	    elfmachine);
143367466Sdim	if (!xlator(dst->d_buf, dsz, src->d_buf, cnt, byteswap)) {
144260684Skaiw		LIBELF_SET_ERROR(DATA, 0);
145260684Skaiw		return (NULL);
146260684Skaiw	}
147260684Skaiw
148260684Skaiw	return (dst);
149260684Skaiw}
150