12de3b87aSKai Wang/*-
22de3b87aSKai Wang * Copyright (c) 2006-2011 Joseph Koshy
32de3b87aSKai Wang * All rights reserved.
42de3b87aSKai Wang *
52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang * modification, are permitted provided that the following conditions
72de3b87aSKai Wang * are met:
82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang *
142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang * SUCH DAMAGE.
252de3b87aSKai Wang */
262de3b87aSKai Wang
272de3b87aSKai Wang#include <assert.h>
282de3b87aSKai Wang#include <libelf.h>
292de3b87aSKai Wang#include <string.h>
302de3b87aSKai Wang
312de3b87aSKai Wang#include "_libelf.h"
322de3b87aSKai Wang
33d003e0d7SEd MasteELFTC_VCSID("$Id: libelf_convert.m4 3712 2019-03-16 22:23:34Z jkoshy $");
342de3b87aSKai Wang
352de3b87aSKai Wang/* WARNING: GENERATED FROM __file__. */
362de3b87aSKai Wang
372de3b87aSKai Wangdivert(-1)
382de3b87aSKai Wang
392de3b87aSKai Wang# Generate conversion routines for converting between in-memory and
402de3b87aSKai Wang# file representations of Elf data structures.
412de3b87aSKai Wang#
422de3b87aSKai Wang# These conversions use the type information defined in `elf_types.m4'.
432de3b87aSKai Wang
442de3b87aSKai Wanginclude(SRCDIR`/elf_types.m4')
452de3b87aSKai Wang
462de3b87aSKai Wang# For the purposes of generating conversion code, ELF types may be
472de3b87aSKai Wang# classified according to the following characteristics:
482de3b87aSKai Wang#
492de3b87aSKai Wang# 1. Whether the ELF type can be directly mapped to an integral C
502de3b87aSKai Wang#    language type.  For example, the ELF_T_WORD type maps directly to
512de3b87aSKai Wang#    a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type.
522de3b87aSKai Wang#
532de3b87aSKai Wang# 2. Whether the type has word size dependent variants.  For example,
542de3b87aSKai Wang#    ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr,
552de3b87aSKai Wang#    and the ELF_T_ADDR and ELF_T_OFF types have integral C types that
562de3b87aSKai Wang#    can be 32- or 64- bit wide.
572de3b87aSKai Wang#
582de3b87aSKai Wang# 3. Whether the ELF types has a fixed representation or not.  For
592de3b87aSKai Wang#    example, the ELF_T_SYM type has a fixed size file representation,
602de3b87aSKai Wang#    some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size
612de3b87aSKai Wang#    representation.
622de3b87aSKai Wang#
632de3b87aSKai Wang# We use m4 macros to generate conversion code for ELF types that have
642de3b87aSKai Wang# a fixed size representation.  Conversion functions for the remaining
652de3b87aSKai Wang# types are coded by hand.
662de3b87aSKai Wang#
672de3b87aSKai Wang#* Handling File and Memory Representations
682de3b87aSKai Wang#
692de3b87aSKai Wang# `In-memory' representations of an Elf data structure use natural
702de3b87aSKai Wang# alignments and native byte ordering.  This allows pointer arithmetic
712de3b87aSKai Wang# and casting to work as expected.  On the other hand, the `file'
722de3b87aSKai Wang# representation of an ELF data structure could possibly be packed
732de3b87aSKai Wang# tighter than its `in-memory' representation, and could be of a
742de3b87aSKai Wang# differing byte order.  Reading ELF objects that are members of `ar'
752de3b87aSKai Wang# archives present an additional complication: `ar' pads file data to
762de3b87aSKai Wang# even addresses, so file data structures in an archive member
772de3b87aSKai Wang# residing inside an `ar' archive could be at misaligned memory
782de3b87aSKai Wang# addresses when brought into memory.
792de3b87aSKai Wang#
802de3b87aSKai Wang# In summary, casting the `char *' pointers that point to memory
812de3b87aSKai Wang# representations (i.e., source pointers for the *_tof() functions and
822de3b87aSKai Wang# the destination pointers for the *_tom() functions), is safe, as
832de3b87aSKai Wang# these pointers should be correctly aligned for the memory type
842de3b87aSKai Wang# already.  However, pointers to file representations have to be
852de3b87aSKai Wang# treated as being potentially unaligned and no casting can be done.
862de3b87aSKai Wang
872de3b87aSKai Wang# NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE
882de3b87aSKai Wangdefine(`NOCVT',`define(`NOCVT_'$1,1)')
892de3b87aSKai Wang
902de3b87aSKai Wang# NOFUNC(TYPE) -- Do not generate a conversion function for TYPE
912de3b87aSKai Wangdefine(`NOFUNC',`define(`NOFUNC_'$1,1)')
922de3b87aSKai Wang
932de3b87aSKai Wang# IGNORE(TYPE) -- Completely ignore the type.
942de3b87aSKai Wangdefine(`IGNORE',`NOCVT($1)NOFUNC($1)')
952de3b87aSKai Wang
962de3b87aSKai Wang# Mark ELF types that should not be processed by the M4 macros below.
972de3b87aSKai Wang
982de3b87aSKai Wang# Types for which we use functions with non-standard names.
992de3b87aSKai WangIGNORE(`BYTE')			# Uses a wrapper around memcpy().
1002de3b87aSKai WangIGNORE(`NOTE')			# Not a fixed size type.
1012de3b87aSKai Wang
1022de3b87aSKai Wang# Types for which we supply hand-coded functions.
1032de3b87aSKai WangNOFUNC(`GNUHASH')		# A type with complex internal structure.
1042de3b87aSKai WangNOFUNC(`VDEF')			# See MAKE_VERSION_CONVERTERS below.
1052de3b87aSKai WangNOFUNC(`VNEED')			# ..
1062de3b87aSKai Wang
1072de3b87aSKai Wang# Unimplemented types.
1082de3b87aSKai WangIGNORE(`MOVEP')
1092de3b87aSKai Wang
1102de3b87aSKai Wang# ELF types that don't exist in a 32-bit world.
1112de3b87aSKai WangNOFUNC(`XWORD32')
1122de3b87aSKai WangNOFUNC(`SXWORD32')
1132de3b87aSKai Wang
1142de3b87aSKai Wang# `Primitive' ELF types are those that are an alias for an integral
1152de3b87aSKai Wang# type.  As they have no internal structure, they can be copied using
1162de3b87aSKai Wang# a `memcpy()', and byteswapped in straightforward way.
1172de3b87aSKai Wang#
1182de3b87aSKai Wang# Mark all ELF types that directly map to integral C types.
1192de3b87aSKai Wangdefine(`PRIM_ADDR',	1)
1202de3b87aSKai Wangdefine(`PRIM_BYTE',	1)
1212de3b87aSKai Wangdefine(`PRIM_HALF',	1)
1222de3b87aSKai Wangdefine(`PRIM_LWORD',	1)
1232de3b87aSKai Wangdefine(`PRIM_OFF',	1)
1242de3b87aSKai Wangdefine(`PRIM_SWORD',	1)
1252de3b87aSKai Wangdefine(`PRIM_SXWORD',	1)
1262de3b87aSKai Wangdefine(`PRIM_WORD',	1)
1272de3b87aSKai Wangdefine(`PRIM_XWORD',	1)
1282de3b87aSKai Wang
1292de3b87aSKai Wang# Note the primitive types that are size-dependent.
1302de3b87aSKai Wangdefine(`SIZEDEP_ADDR',	1)
1312de3b87aSKai Wangdefine(`SIZEDEP_OFF',	1)
1322de3b87aSKai Wang
1332de3b87aSKai Wang# Generate conversion functions for primitive types.
1342de3b87aSKai Wang#
1352de3b87aSKai Wang# Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE)
1362de3b87aSKai Wang# `$1': Name of the ELF type.
1372de3b87aSKai Wang# `$2': C structure name suffix.
1382de3b87aSKai Wang# `$3': ELF class specifier for types, one of [`32', `64'].
1392de3b87aSKai Wang# `$4': Additional ELF class specifier, one of [`', `32', `64'].
1402de3b87aSKai Wang#
1412de3b87aSKai Wang# Generates a pair of conversion functions.
1422de3b87aSKai Wangdefine(`MAKEPRIMFUNCS',`
1432de3b87aSKai Wangstatic int
144cf781b2eSEd Maste_libelf_cvt_$1$4_tof(unsigned char *dst, size_t dsz, unsigned char *src,
145cf781b2eSEd Maste    size_t count, int byteswap)
1462de3b87aSKai Wang{
1472de3b87aSKai Wang	Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src;
1482de3b87aSKai Wang	size_t c;
1492de3b87aSKai Wang
1502de3b87aSKai Wang	(void) dsz;
1512de3b87aSKai Wang
1522de3b87aSKai Wang	if (!byteswap) {
1532de3b87aSKai Wang		(void) memcpy(dst, src, count * sizeof(*s));
1542de3b87aSKai Wang		return (1);
1552de3b87aSKai Wang	}
1562de3b87aSKai Wang
1572de3b87aSKai Wang	for (c = 0; c < count; c++) {
1582de3b87aSKai Wang		t = *s++;
1592de3b87aSKai Wang		SWAP_$1$4(t);
1602de3b87aSKai Wang		WRITE_$1$4(dst,t);
1612de3b87aSKai Wang	}
1622de3b87aSKai Wang
1632de3b87aSKai Wang	return (1);
1642de3b87aSKai Wang}
1652de3b87aSKai Wang
1662de3b87aSKai Wangstatic int
167cf781b2eSEd Maste_libelf_cvt_$1$4_tom(unsigned char *dst, size_t dsz, unsigned char *src,
168cf781b2eSEd Maste    size_t count, int byteswap)
1692de3b87aSKai Wang{
1702de3b87aSKai Wang	Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst;
1712de3b87aSKai Wang	size_t c;
1722de3b87aSKai Wang
1732de3b87aSKai Wang	if (dsz < count * sizeof(Elf$3_$2))
1742de3b87aSKai Wang		return (0);
1752de3b87aSKai Wang
1762de3b87aSKai Wang	if (!byteswap) {
1772de3b87aSKai Wang		(void) memcpy(dst, src, count * sizeof(*d));
1782de3b87aSKai Wang		return (1);
1792de3b87aSKai Wang	}
1802de3b87aSKai Wang
1812de3b87aSKai Wang	for (c = 0; c < count; c++) {
1822de3b87aSKai Wang		READ_$1$4(src,t);
1832de3b87aSKai Wang		SWAP_$1$4(t);
1842de3b87aSKai Wang		*d++ = t;
1852de3b87aSKai Wang	}
1862de3b87aSKai Wang
1872de3b87aSKai Wang	return (1);
1882de3b87aSKai Wang}
1892de3b87aSKai Wang')
1902de3b87aSKai Wang
1912de3b87aSKai Wang#
1922de3b87aSKai Wang# Handling composite ELF types
1932de3b87aSKai Wang#
1942de3b87aSKai Wang
1952de3b87aSKai Wang# SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field.
1962de3b87aSKai Wangdefine(`SWAP_FIELD',
1972de3b87aSKai Wang  `ifdef(`SIZEDEP_'$2,
1982de3b87aSKai Wang    `SWAP_$2'SZ()`(t.$1);
1992de3b87aSKai Wang			',
2002de3b87aSKai Wang    `SWAP_$2(t.$1);
2012de3b87aSKai Wang			')')
2022de3b87aSKai Wang
2032de3b87aSKai Wang# SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition.
2042de3b87aSKai Wangdefine(`SWAP_MEMBERS',
2052de3b87aSKai Wang  `ifelse($#,1,`/**/',
2062de3b87aSKai Wang     `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
2072de3b87aSKai Wang
2082de3b87aSKai Wang# SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure.
2092de3b87aSKai Wangdefine(`SWAP_STRUCT',
2102de3b87aSKai Wang  `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
2112de3b87aSKai Wang			SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
2122de3b87aSKai Wang
2132de3b87aSKai Wang# WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field.
2142de3b87aSKai Wangdefine(`WRITE_FIELD',
2152de3b87aSKai Wang  `ifdef(`SIZEDEP_'$2,
2162de3b87aSKai Wang    `WRITE_$2'SZ()`(dst,t.$1);
2172de3b87aSKai Wang		',
2182de3b87aSKai Wang    `WRITE_$2(dst,t.$1);
2192de3b87aSKai Wang		')')
2202de3b87aSKai Wang
2212de3b87aSKai Wang# WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
2222de3b87aSKai Wangdefine(`WRITE_MEMBERS',
2232de3b87aSKai Wang  `ifelse($#,1,`/**/',
2242de3b87aSKai Wang    `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
2252de3b87aSKai Wang
2262de3b87aSKai Wang# WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure.
2272de3b87aSKai Wangdefine(`WRITE_STRUCT',
2282de3b87aSKai Wang  `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
2292de3b87aSKai Wang		WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
2302de3b87aSKai Wang
2312de3b87aSKai Wang# READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field.
2322de3b87aSKai Wangdefine(`READ_FIELD',
2332de3b87aSKai Wang  `ifdef(`SIZEDEP_'$2,
2342de3b87aSKai Wang    `READ_$2'SZ()`(s,t.$1);
2352de3b87aSKai Wang		',
2362de3b87aSKai Wang    `READ_$2(s,t.$1);
2372de3b87aSKai Wang		')')
2382de3b87aSKai Wang
2392de3b87aSKai Wang# READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
2402de3b87aSKai Wangdefine(`READ_MEMBERS',
2412de3b87aSKai Wang  `ifelse($#,1,`/**/',
2422de3b87aSKai Wang    `READ_FIELD($1)READ_MEMBERS(shift($@))')')
2432de3b87aSKai Wang
2442de3b87aSKai Wang# READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure.
2452de3b87aSKai Wangdefine(`READ_STRUCT',
2462de3b87aSKai Wang  `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
2472de3b87aSKai Wang		READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
2482de3b87aSKai Wang
2492de3b87aSKai Wang
2502de3b87aSKai Wang# MAKECOMPFUNCS -- Generate converters for composite ELF structures.
2512de3b87aSKai Wang#
2522de3b87aSKai Wang# When converting data to file representation, the source pointer will
2532de3b87aSKai Wang# be naturally aligned for a data structure's in-memory
2542de3b87aSKai Wang# representation.  When converting data to memory, the destination
2552de3b87aSKai Wang# pointer will be similarly aligned.
2562de3b87aSKai Wang#
2572de3b87aSKai Wang# For in-place conversions, when converting to file representations,
2582de3b87aSKai Wang# the source buffer is large enough to hold `file' data.  When
2592de3b87aSKai Wang# converting from file to memory, we need to be careful to work
2602de3b87aSKai Wang# `backwards', to avoid overwriting unconverted data.
2612de3b87aSKai Wang#
2622de3b87aSKai Wang# Macro use:
2632de3b87aSKai Wang# `$1': Name of the ELF type.
2642de3b87aSKai Wang# `$2': C structure name suffix.
2652de3b87aSKai Wang# `$3': ELF class specifier, one of [`', `32', `64']
2662de3b87aSKai Wangdefine(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',`
2672de3b87aSKai Wangstatic int
268cf781b2eSEd Maste_libelf_cvt_$1$3_tof(unsigned char *dst, size_t dsz, unsigned char *src,
269cf781b2eSEd Maste    size_t count, int byteswap)
2702de3b87aSKai Wang{
2712de3b87aSKai Wang	Elf$3_$2	t, *s;
2722de3b87aSKai Wang	size_t c;
2732de3b87aSKai Wang
2742de3b87aSKai Wang	(void) dsz;
2752de3b87aSKai Wang
2762de3b87aSKai Wang	s = (Elf$3_$2 *) (uintptr_t) src;
2772de3b87aSKai Wang	for (c = 0; c < count; c++) {
2782de3b87aSKai Wang		t = *s++;
2792de3b87aSKai Wang		if (byteswap) {
2802de3b87aSKai Wang			SWAP_STRUCT($2,$3)
2812de3b87aSKai Wang		}
2822de3b87aSKai Wang		WRITE_STRUCT($2,$3)
2832de3b87aSKai Wang	}
2842de3b87aSKai Wang
2852de3b87aSKai Wang	return (1);
2862de3b87aSKai Wang}
2872de3b87aSKai Wang
2882de3b87aSKai Wangstatic int
289cf781b2eSEd Maste_libelf_cvt_$1$3_tom(unsigned char *dst, size_t dsz, unsigned char *src,
290cf781b2eSEd Maste    size_t count, int byteswap)
2912de3b87aSKai Wang{
2922de3b87aSKai Wang	Elf$3_$2	t, *d;
293cf781b2eSEd Maste	unsigned char	*s,*s0;
2942de3b87aSKai Wang	size_t		fsz;
2952de3b87aSKai Wang
2962de3b87aSKai Wang	fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT);
2972de3b87aSKai Wang	d   = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
298cf781b2eSEd Maste	s0  = src + (count - 1) * fsz;
2992de3b87aSKai Wang
3002de3b87aSKai Wang	if (dsz < count * sizeof(Elf$3_$2))
3012de3b87aSKai Wang		return (0);
3022de3b87aSKai Wang
3032de3b87aSKai Wang	while (count--) {
3042de3b87aSKai Wang		s = s0;
3052de3b87aSKai Wang		READ_STRUCT($2,$3)
3062de3b87aSKai Wang		if (byteswap) {
3072de3b87aSKai Wang			SWAP_STRUCT($2,$3)
3082de3b87aSKai Wang		}
3092de3b87aSKai Wang		*d-- = t; s0 -= fsz;
3102de3b87aSKai Wang	}
3112de3b87aSKai Wang
3122de3b87aSKai Wang	return (1);
3132de3b87aSKai Wang}
3142de3b87aSKai Wang')')
3152de3b87aSKai Wang
3162de3b87aSKai Wang# MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE)
3172de3b87aSKai Wang#
3182de3b87aSKai Wang# Make type convertor functions from the type definition
3192de3b87aSKai Wang# of the ELF type:
3202de3b87aSKai Wang# - Skip convertors marked as `NOFUNC'.
3212de3b87aSKai Wang# - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate.
3222de3b87aSKai Wangdefine(`MAKE_TYPE_CONVERTER',
3232de3b87aSKai Wang  `ifdef(`NOFUNC_'$1,`',
3242de3b87aSKai Wang    `ifdef(`PRIM_'$1,
3252de3b87aSKai Wang      `ifdef(`SIZEDEP_'$1,
3262de3b87aSKai Wang	`MAKEPRIMFUNCS($1,$2,32,32)dnl
3272de3b87aSKai Wang	 MAKEPRIMFUNCS($1,$2,64,64)',
3282de3b87aSKai Wang	`MAKEPRIMFUNCS($1,$2,64)')',
3292de3b87aSKai Wang      `MAKECOMPFUNCS($1,$2,32)dnl
3302de3b87aSKai Wang       MAKECOMPFUNCS($1,$2,64)')')')
3312de3b87aSKai Wang
3322de3b87aSKai Wang# MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions.
3332de3b87aSKai Wangdefine(`MAKE_TYPE_CONVERTERS',
3342de3b87aSKai Wang  `ifelse($#,1,`',
3352de3b87aSKai Wang    `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
3362de3b87aSKai Wang
3372de3b87aSKai Wang
3382de3b87aSKai Wang#
3392de3b87aSKai Wang# Macros to generate entries for the table of convertors.
3402de3b87aSKai Wang#
3412de3b87aSKai Wang
3422de3b87aSKai Wang# CONV(ELFTYPE,SIZE,DIRECTION)
3432de3b87aSKai Wang#
3442de3b87aSKai Wang# Generate the name of a convertor function.
3452de3b87aSKai Wangdefine(`CONV',
3462de3b87aSKai Wang  `ifdef(`NOFUNC_'$1$2,
3472de3b87aSKai Wang    `.$3$2 = NULL',
3482de3b87aSKai Wang    `ifdef(`PRIM_'$1,
3492de3b87aSKai Wang      `ifdef(`SIZEDEP_'$1,
3502de3b87aSKai Wang	`.$3$2 = _libelf_cvt_$1$2_$3',
3512de3b87aSKai Wang	`.$3$2 = _libelf_cvt_$1_$3')',
3522de3b87aSKai Wang      `.$3$2 = _libelf_cvt_$1$2_$3')')')
3532de3b87aSKai Wang
3542de3b87aSKai Wang# CONVERTER_NAME(ELFTYPE)
3552de3b87aSKai Wang#
3562de3b87aSKai Wang# Generate the contents of one `struct cvt' instance.
3572de3b87aSKai Wangdefine(`CONVERTER_NAME',
3582de3b87aSKai Wang  `ifdef(`NOCVT_'$1,`',
3592de3b87aSKai Wang    `	[ELF_T_$1] = {
3602de3b87aSKai Wang		CONV($1,32,tof),
3612de3b87aSKai Wang		CONV($1,32,tom),
3622de3b87aSKai Wang		CONV($1,64,tof),
3632de3b87aSKai Wang		CONV($1,64,tom)
3642de3b87aSKai Wang	},
3652de3b87aSKai Wang
3662de3b87aSKai Wang')')
3672de3b87aSKai Wang
3682de3b87aSKai Wang# CONVERTER_NAMES(ELFTYPELIST)
3692de3b87aSKai Wang#
3702de3b87aSKai Wang# Generate the `struct cvt[]' array.
3712de3b87aSKai Wangdefine(`CONVERTER_NAMES',
3722de3b87aSKai Wang  `ifelse($#,1,`',
3732de3b87aSKai Wang    `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
3742de3b87aSKai Wang
3752de3b87aSKai Wang#
3762de3b87aSKai Wang# Handling ELF version sections.
3772de3b87aSKai Wang#
3782de3b87aSKai Wang
3792de3b87aSKai Wang# _FSZ(FIELD,BASETYPE) - return the file size for a field.
3802de3b87aSKai Wangdefine(`_FSZ',
3812de3b87aSKai Wang  `ifelse($2,`HALF',2,
3822de3b87aSKai Wang     $2,`WORD',4)')
3832de3b87aSKai Wang
3842de3b87aSKai Wang# FSZ(STRUCT) - determine the file size of a structure.
3852de3b87aSKai Wangdefine(`FSZ',
3862de3b87aSKai Wang  `ifelse($#,1,0,
3872de3b87aSKai Wang    `eval(_FSZ($1) + FSZ(shift($@)))')')
3882de3b87aSKai Wang
3892de3b87aSKai Wang# MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion
3902de3b87aSKai Wang# functions for versioning structures.
3912de3b87aSKai Wangdefine(`MAKE_VERSION_CONVERTERS',
3922de3b87aSKai Wang  `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32)
3932de3b87aSKai Wang   MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)')
3942de3b87aSKai Wang
3952de3b87aSKai Wang# MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a
3962de3b87aSKai Wang# conversion function.
3972de3b87aSKai Wangdefine(`MAKE_VERSION_CONVERTER',`
3982de3b87aSKai Wangstatic int
399cf781b2eSEd Maste_libelf_cvt_$1$5_tof(unsigned char *dst, size_t dsz, unsigned char *src,
400cf781b2eSEd Maste    size_t count, int byteswap)
4012de3b87aSKai Wang{
4022de3b87aSKai Wang	Elf$5_$2	t;
4032de3b87aSKai Wang	Elf$5_$3	a;
4042de3b87aSKai Wang	const size_t	verfsz = FSZ(Elf$5_$2_DEF);
4052de3b87aSKai Wang	const size_t	auxfsz = FSZ(Elf$5_$3_DEF);
4062de3b87aSKai Wang	const size_t	vermsz = sizeof(Elf$5_$2);
4072de3b87aSKai Wang	const size_t	auxmsz = sizeof(Elf$5_$3);
408cf781b2eSEd Maste	unsigned char * const dstend = dst + dsz;
409cf781b2eSEd Maste	unsigned char * const srcend = src + count;
410cf781b2eSEd Maste	unsigned char	*dtmp, *dstaux, *srcaux;
4112de3b87aSKai Wang	Elf$5_Word	aux, anext, cnt, vnext;
4122de3b87aSKai Wang
413cf781b2eSEd Maste	for (dtmp = dst, vnext = ~0U;
4142de3b87aSKai Wang	     vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend;
4152de3b87aSKai Wang	     dtmp += vnext, src += vnext) {
4162de3b87aSKai Wang
4172de3b87aSKai Wang		/* Read in an Elf$5_$2 structure. */
4182de3b87aSKai Wang		t = *((Elf$5_$2 *) (uintptr_t) src);
4192de3b87aSKai Wang
4202de3b87aSKai Wang		aux = t.$4_aux;
4212de3b87aSKai Wang		cnt = t.$4_cnt;
4222de3b87aSKai Wang		vnext = t.$4_next;
4232de3b87aSKai Wang
4242de3b87aSKai Wang		if (byteswap) {
4252de3b87aSKai Wang			SWAP_STRUCT($2, $5)
4262de3b87aSKai Wang		}
4272de3b87aSKai Wang
4282de3b87aSKai Wang		dst = dtmp;
4292de3b87aSKai Wang		WRITE_STRUCT($2, $5)
4302de3b87aSKai Wang
4312de3b87aSKai Wang		if (aux < verfsz)
4322de3b87aSKai Wang			return (0);
4332de3b87aSKai Wang
4342de3b87aSKai Wang		/* Process AUX entries. */
435cf781b2eSEd Maste		for (anext = ~0U, dstaux = dtmp + aux, srcaux = src + aux;
4362de3b87aSKai Wang		     cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend &&
4372de3b87aSKai Wang			srcaux + auxmsz <= srcend;
4382de3b87aSKai Wang		     dstaux += anext, srcaux += anext, cnt--) {
4392de3b87aSKai Wang
4402de3b87aSKai Wang			/* Read in an Elf$5_$3 structure. */
4412de3b87aSKai Wang			a = *((Elf$5_$3 *) (uintptr_t) srcaux);
4422de3b87aSKai Wang			anext = a.$4a_next;
4432de3b87aSKai Wang
4442de3b87aSKai Wang			if (byteswap) {
4452de3b87aSKai Wang				pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
4462de3b87aSKai Wang			}
4472de3b87aSKai Wang
4482de3b87aSKai Wang			dst = dstaux;
4492de3b87aSKai Wang			pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t')
4502de3b87aSKai Wang		}
4512de3b87aSKai Wang
4522de3b87aSKai Wang		if (anext || cnt)
4532de3b87aSKai Wang			return (0);
4542de3b87aSKai Wang	}
4552de3b87aSKai Wang
4562de3b87aSKai Wang	if (vnext)
4572de3b87aSKai Wang		return (0);
4582de3b87aSKai Wang
4592de3b87aSKai Wang	return (1);
4602de3b87aSKai Wang}
4612de3b87aSKai Wang
4622de3b87aSKai Wangstatic int
463cf781b2eSEd Maste_libelf_cvt_$1$5_tom(unsigned char *dst, size_t dsz, unsigned char *src,
464cf781b2eSEd Maste    size_t count, int byteswap)
4652de3b87aSKai Wang{
4662de3b87aSKai Wang	Elf$5_$2	t, *dp;
4672de3b87aSKai Wang	Elf$5_$3	a, *ap;
4682de3b87aSKai Wang	const size_t	verfsz = FSZ(Elf$5_$2_DEF);
4692de3b87aSKai Wang	const size_t	auxfsz = FSZ(Elf$5_$3_DEF);
4702de3b87aSKai Wang	const size_t	vermsz = sizeof(Elf$5_$2);
4712de3b87aSKai Wang	const size_t	auxmsz = sizeof(Elf$5_$3);
472cf781b2eSEd Maste	unsigned char * const dstend = dst + dsz;
473cf781b2eSEd Maste	unsigned char * const srcend = src + count;
474cf781b2eSEd Maste	unsigned char	*dstaux, *s, *srcaux, *stmp;
4752de3b87aSKai Wang	Elf$5_Word	aux, anext, cnt, vnext;
4762de3b87aSKai Wang
477cf781b2eSEd Maste	for (stmp = src, vnext = ~0U;
4782de3b87aSKai Wang	     vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
4792de3b87aSKai Wang	     stmp += vnext, dst += vnext) {
4802de3b87aSKai Wang
4812de3b87aSKai Wang		/* Read in a $1 structure. */
4822de3b87aSKai Wang		s = stmp;
4832de3b87aSKai Wang		READ_STRUCT($2, $5)
4842de3b87aSKai Wang		if (byteswap) {
4852de3b87aSKai Wang			SWAP_STRUCT($2, $5)
4862de3b87aSKai Wang		}
4872de3b87aSKai Wang
4882de3b87aSKai Wang		dp = (Elf$5_$2 *) (uintptr_t) dst;
4892de3b87aSKai Wang		*dp = t;
4902de3b87aSKai Wang
4912de3b87aSKai Wang		aux = t.$4_aux;
4922de3b87aSKai Wang		cnt = t.$4_cnt;
4932de3b87aSKai Wang		vnext = t.$4_next;
4942de3b87aSKai Wang
4952de3b87aSKai Wang		if (aux < vermsz)
4962de3b87aSKai Wang			return (0);
4972de3b87aSKai Wang
4982de3b87aSKai Wang		/* Process AUX entries. */
499cf781b2eSEd Maste		for (anext = ~0U, dstaux = dst + aux, srcaux = stmp + aux;
5002de3b87aSKai Wang		     cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend &&
5012de3b87aSKai Wang			srcaux + auxfsz <= srcend;
5022de3b87aSKai Wang		     dstaux += anext, srcaux += anext, cnt--) {
5032de3b87aSKai Wang
5042de3b87aSKai Wang			s = srcaux;
5052de3b87aSKai Wang			pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t')
5062de3b87aSKai Wang
5072de3b87aSKai Wang			if (byteswap) {
5082de3b87aSKai Wang				pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
5092de3b87aSKai Wang			}
5102de3b87aSKai Wang
5112de3b87aSKai Wang			anext = a.$4a_next;
5122de3b87aSKai Wang
5132de3b87aSKai Wang			ap = ((Elf$5_$3 *) (uintptr_t) dstaux);
5142de3b87aSKai Wang			*ap = a;
5152de3b87aSKai Wang		}
5162de3b87aSKai Wang
5172de3b87aSKai Wang		if (anext || cnt)
5182de3b87aSKai Wang			return (0);
5192de3b87aSKai Wang	}
5202de3b87aSKai Wang
5212de3b87aSKai Wang	if (vnext)
5222de3b87aSKai Wang		return (0);
5232de3b87aSKai Wang
5242de3b87aSKai Wang	return (1);
5252de3b87aSKai Wang}')
5262de3b87aSKai Wang
5272de3b87aSKai Wangdivert(0)
5282de3b87aSKai Wang
5292de3b87aSKai Wang/*
5302de3b87aSKai Wang * C macros to byte swap integral quantities.
5312de3b87aSKai Wang */
5322de3b87aSKai Wang
5332de3b87aSKai Wang#define	SWAP_BYTE(X)	do { (void) (X); } while (0)
5342de3b87aSKai Wang#define	SWAP_IDENT(X)	do { (void) (X); } while (0)
5352de3b87aSKai Wang#define	SWAP_HALF(X)	do {						\
5362de3b87aSKai Wang		uint16_t _x = (uint16_t) (X);				\
537cf781b2eSEd Maste		uint32_t _t = _x & 0xFFU;				\
538cf781b2eSEd Maste		_t <<= 8U; _x >>= 8U; _t |= _x & 0xFFU;			\
539cf781b2eSEd Maste		(X) = (uint16_t) _t;					\
5402de3b87aSKai Wang	} while (0)
541cf781b2eSEd Maste#define	_SWAP_WORD(X, T) do {						\
5422de3b87aSKai Wang		uint32_t _x = (uint32_t) (X);				\
5432de3b87aSKai Wang		uint32_t _t = _x & 0xFF;				\
5442de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5452de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5462de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
547cf781b2eSEd Maste		(X) = (T) _t;						\
5482de3b87aSKai Wang	} while (0)
549cf781b2eSEd Maste#define	SWAP_ADDR32(X)	_SWAP_WORD(X, Elf32_Addr)
550cf781b2eSEd Maste#define	SWAP_OFF32(X)	_SWAP_WORD(X, Elf32_Off)
551cf781b2eSEd Maste#define	SWAP_SWORD(X)	_SWAP_WORD(X, Elf32_Sword)
552cf781b2eSEd Maste#define	SWAP_WORD(X)	_SWAP_WORD(X, Elf32_Word)
553cf781b2eSEd Maste#define	_SWAP_WORD64(X, T) do {						\
5542de3b87aSKai Wang		uint64_t _x = (uint64_t) (X);				\
5552de3b87aSKai Wang		uint64_t _t = _x & 0xFF;				\
5562de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5572de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5582de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5592de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5602de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5612de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
5622de3b87aSKai Wang		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
563cf781b2eSEd Maste		(X) = (T) _t;						\
5642de3b87aSKai Wang	} while (0)
565cf781b2eSEd Maste#define	SWAP_ADDR64(X)	_SWAP_WORD64(X, Elf64_Addr)
566cf781b2eSEd Maste#define	SWAP_LWORD(X)	_SWAP_WORD64(X, Elf64_Lword)
567cf781b2eSEd Maste#define	SWAP_OFF64(X)	_SWAP_WORD64(X, Elf64_Off)
568cf781b2eSEd Maste#define	SWAP_SXWORD(X)	_SWAP_WORD64(X, Elf64_Sxword)
569cf781b2eSEd Maste#define	SWAP_XWORD(X)	_SWAP_WORD64(X, Elf64_Xword)
5702de3b87aSKai Wang
5712de3b87aSKai Wang/*
5722de3b87aSKai Wang * C macros to write out various integral values.
5732de3b87aSKai Wang *
5742de3b87aSKai Wang * Note:
5752de3b87aSKai Wang * - The destination pointer could be unaligned.
5762de3b87aSKai Wang * - Values are written out in native byte order.
5772de3b87aSKai Wang * - The destination pointer is incremented after the write.
5782de3b87aSKai Wang */
5792de3b87aSKai Wang#define	WRITE_BYTE(P,X) do {						\
580cf781b2eSEd Maste		unsigned char *const _p = (unsigned char *) (P);	\
581cf781b2eSEd Maste		_p[0]		= (unsigned char) (X);			\
5822de3b87aSKai Wang		(P)		= _p + 1;				\
5832de3b87aSKai Wang	} while (0)
5842de3b87aSKai Wang#define	WRITE_HALF(P,X)	do {						\
5852de3b87aSKai Wang		uint16_t _t	= (X);					\
586cf781b2eSEd Maste		unsigned char *const _p	= (unsigned char *) (P);	\
587cf781b2eSEd Maste		const unsigned char *const _q = (unsigned char *) &_t;	\
5882de3b87aSKai Wang		_p[0]		= _q[0];				\
5892de3b87aSKai Wang		_p[1]		= _q[1];				\
5902de3b87aSKai Wang		(P)		= _p + 2;				\
5912de3b87aSKai Wang	} while (0)
5922de3b87aSKai Wang#define	WRITE_WORD(P,X) do {						\
593cf781b2eSEd Maste		uint32_t _t	= (uint32_t) (X);			\
594cf781b2eSEd Maste		unsigned char *const _p	= (unsigned char *) (P);	\
595cf781b2eSEd Maste		const unsigned char *const _q = (unsigned char *) &_t;	\
5962de3b87aSKai Wang		_p[0]		= _q[0];				\
5972de3b87aSKai Wang		_p[1]		= _q[1];				\
5982de3b87aSKai Wang		_p[2]		= _q[2];				\
5992de3b87aSKai Wang		_p[3]		= _q[3];				\
6002de3b87aSKai Wang		(P)		= _p + 4;				\
6012de3b87aSKai Wang	} while (0)
6022de3b87aSKai Wang#define	WRITE_ADDR32(P,X)	WRITE_WORD(P,X)
6032de3b87aSKai Wang#define	WRITE_OFF32(P,X)	WRITE_WORD(P,X)
6042de3b87aSKai Wang#define	WRITE_SWORD(P,X)	WRITE_WORD(P,X)
6052de3b87aSKai Wang#define	WRITE_WORD64(P,X)	do {					\
606cf781b2eSEd Maste		uint64_t _t	= (uint64_t) (X);			\
607cf781b2eSEd Maste		unsigned char *const _p	= (unsigned char *) (P);	\
608cf781b2eSEd Maste		const unsigned char *const _q = (unsigned char *) &_t;	\
6092de3b87aSKai Wang		_p[0]		= _q[0];				\
6102de3b87aSKai Wang		_p[1]		= _q[1];				\
6112de3b87aSKai Wang		_p[2]		= _q[2];				\
6122de3b87aSKai Wang		_p[3]		= _q[3];				\
6132de3b87aSKai Wang		_p[4]		= _q[4];				\
6142de3b87aSKai Wang		_p[5]		= _q[5];				\
6152de3b87aSKai Wang		_p[6]		= _q[6];				\
6162de3b87aSKai Wang		_p[7]		= _q[7];				\
6172de3b87aSKai Wang		(P)		= _p + 8;				\
6182de3b87aSKai Wang	} while (0)
6192de3b87aSKai Wang#define	WRITE_ADDR64(P,X)	WRITE_WORD64(P,X)
6202de3b87aSKai Wang#define	WRITE_LWORD(P,X)	WRITE_WORD64(P,X)
6212de3b87aSKai Wang#define	WRITE_OFF64(P,X)	WRITE_WORD64(P,X)
6222de3b87aSKai Wang#define	WRITE_SXWORD(P,X)	WRITE_WORD64(P,X)
6232de3b87aSKai Wang#define	WRITE_XWORD(P,X)	WRITE_WORD64(P,X)
6242de3b87aSKai Wang#define	WRITE_IDENT(P,X)	do {					\
6252de3b87aSKai Wang		(void) memcpy((P), (X), sizeof((X)));			\
6262de3b87aSKai Wang		(P)		= (P) + EI_NIDENT;			\
6272de3b87aSKai Wang	} while (0)
6282de3b87aSKai Wang
6292de3b87aSKai Wang/*
6302de3b87aSKai Wang * C macros to read in various integral values.
6312de3b87aSKai Wang *
6322de3b87aSKai Wang * Note:
6332de3b87aSKai Wang * - The source pointer could be unaligned.
6342de3b87aSKai Wang * - Values are read in native byte order.
6352de3b87aSKai Wang * - The source pointer is incremented appropriately.
6362de3b87aSKai Wang */
6372de3b87aSKai Wang
6382de3b87aSKai Wang#define	READ_BYTE(P,X)	do {						\
639cf781b2eSEd Maste		const unsigned char *const _p =				\
640cf781b2eSEd Maste			(const unsigned char *) (P);			\
6412de3b87aSKai Wang		(X)		= _p[0];				\
6422de3b87aSKai Wang		(P)		= (P) + 1;				\
6432de3b87aSKai Wang	} while (0)
6442de3b87aSKai Wang#define	READ_HALF(P,X)	do {						\
6452de3b87aSKai Wang		uint16_t _t;						\
646cf781b2eSEd Maste		unsigned char *const _q = (unsigned char *) &_t;	\
647cf781b2eSEd Maste		const unsigned char *const _p =				\
648cf781b2eSEd Maste			(const unsigned char *) (P);			\
6492de3b87aSKai Wang		_q[0]		= _p[0];				\
6502de3b87aSKai Wang		_q[1]		= _p[1];				\
6512de3b87aSKai Wang		(P)		= (P) + 2;				\
6522de3b87aSKai Wang		(X)		= _t;					\
6532de3b87aSKai Wang	} while (0)
654cf781b2eSEd Maste#define	_READ_WORD(P,X,T) do {						\
6552de3b87aSKai Wang		uint32_t _t;						\
656cf781b2eSEd Maste		unsigned char *const _q = (unsigned char *) &_t;	\
657cf781b2eSEd Maste		const unsigned char *const _p =				\
658cf781b2eSEd Maste			(const unsigned char *) (P);			\
6592de3b87aSKai Wang		_q[0]		= _p[0];				\
6602de3b87aSKai Wang		_q[1]		= _p[1];				\
6612de3b87aSKai Wang		_q[2]		= _p[2];				\
6622de3b87aSKai Wang		_q[3]		= _p[3];				\
6632de3b87aSKai Wang		(P)		= (P) + 4;				\
664cf781b2eSEd Maste		(X)		= (T) _t;				\
6652de3b87aSKai Wang	} while (0)
666cf781b2eSEd Maste#define	READ_ADDR32(P,X)	_READ_WORD(P, X, Elf32_Addr)
667cf781b2eSEd Maste#define	READ_OFF32(P,X)		_READ_WORD(P, X, Elf32_Off)
668cf781b2eSEd Maste#define	READ_SWORD(P,X)		_READ_WORD(P, X, Elf32_Sword)
669cf781b2eSEd Maste#define	READ_WORD(P,X)		_READ_WORD(P, X, Elf32_Word)
670cf781b2eSEd Maste#define	_READ_WORD64(P,X,T)	do {					\
6712de3b87aSKai Wang		uint64_t _t;						\
672cf781b2eSEd Maste		unsigned char *const _q = (unsigned char *) &_t;	\
673cf781b2eSEd Maste		const unsigned char *const _p =				\
674cf781b2eSEd Maste			(const unsigned char *) (P);			\
6752de3b87aSKai Wang		_q[0]		= _p[0];				\
6762de3b87aSKai Wang		_q[1]		= _p[1];				\
6772de3b87aSKai Wang		_q[2]		= _p[2];				\
6782de3b87aSKai Wang		_q[3]		= _p[3];				\
6792de3b87aSKai Wang		_q[4]		= _p[4];				\
6802de3b87aSKai Wang		_q[5]		= _p[5];				\
6812de3b87aSKai Wang		_q[6]		= _p[6];				\
6822de3b87aSKai Wang		_q[7]		= _p[7];				\
6832de3b87aSKai Wang		(P)		= (P) + 8;				\
684cf781b2eSEd Maste		(X)		= (T) _t;				\
6852de3b87aSKai Wang	} while (0)
686cf781b2eSEd Maste#define	READ_ADDR64(P,X)	_READ_WORD64(P, X, Elf64_Addr)
687cf781b2eSEd Maste#define	READ_LWORD(P,X)		_READ_WORD64(P, X, Elf64_Lword)
688cf781b2eSEd Maste#define	READ_OFF64(P,X)		_READ_WORD64(P, X, Elf64_Off)
689cf781b2eSEd Maste#define	READ_SXWORD(P,X)	_READ_WORD64(P, X, Elf64_Sxword)
690cf781b2eSEd Maste#define	READ_XWORD(P,X)		_READ_WORD64(P, X, Elf64_Xword)
6912de3b87aSKai Wang#define	READ_IDENT(P,X)		do {					\
6922de3b87aSKai Wang		(void) memcpy((X), (P), sizeof((X)));			\
6932de3b87aSKai Wang		(P)		= (P) + EI_NIDENT;			\
6942de3b87aSKai Wang	} while (0)
6952de3b87aSKai Wang
6962de3b87aSKai Wang#define	ROUNDUP2(V,N)	(V) = ((((V) + (N) - 1)) & ~((N) - 1))
6972de3b87aSKai Wang
6982de3b87aSKai Wang/*[*/
6992de3b87aSKai WangMAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
7002de3b87aSKai WangMAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd)
7012de3b87aSKai WangMAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn)
7022de3b87aSKai Wang/*]*/
7032de3b87aSKai Wang
7042de3b87aSKai Wang/*
7052de3b87aSKai Wang * Sections of type ELF_T_BYTE are never byteswapped, consequently a
7062de3b87aSKai Wang * simple memcpy suffices for both directions of conversion.
7072de3b87aSKai Wang */
7082de3b87aSKai Wang
7092de3b87aSKai Wangstatic int
710cf781b2eSEd Maste_libelf_cvt_BYTE_tox(unsigned char *dst, size_t dsz, unsigned char *src,
711cf781b2eSEd Maste    size_t count, int byteswap)
7122de3b87aSKai Wang{
7132de3b87aSKai Wang	(void) byteswap;
7142de3b87aSKai Wang	if (dsz < count)
7152de3b87aSKai Wang		return (0);
7162de3b87aSKai Wang	if (dst != src)
7172de3b87aSKai Wang		(void) memcpy(dst, src, count);
7182de3b87aSKai Wang	return (1);
7192de3b87aSKai Wang}
7202de3b87aSKai Wang
7212de3b87aSKai Wang/*
7222de3b87aSKai Wang * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
7232de3b87aSKai Wang * words.  Bloom filter data comes next, followed by hash buckets and the
7242de3b87aSKai Wang * hash chain.
7252de3b87aSKai Wang *
7262de3b87aSKai Wang * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
7272de3b87aSKai Wang * wide on ELFCLASS32 objects.  The other objects in this section are 32
7282de3b87aSKai Wang * bits wide.
7292de3b87aSKai Wang *
7302de3b87aSKai Wang * Argument `srcsz' denotes the number of bytes to be converted.  In the
7312de3b87aSKai Wang * 32-bit case we need to translate `srcsz' to a count of 32-bit words.
7322de3b87aSKai Wang */
7332de3b87aSKai Wang
7342de3b87aSKai Wangstatic int
735cf781b2eSEd Maste_libelf_cvt_GNUHASH32_tom(unsigned char *dst, size_t dsz, unsigned char *src,
736cf781b2eSEd Maste    size_t srcsz, int byteswap)
7372de3b87aSKai Wang{
7382de3b87aSKai Wang	return (_libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
7392de3b87aSKai Wang		byteswap));
7402de3b87aSKai Wang}
7412de3b87aSKai Wang
7422de3b87aSKai Wangstatic int
743cf781b2eSEd Maste_libelf_cvt_GNUHASH32_tof(unsigned char *dst, size_t dsz, unsigned char *src,
744cf781b2eSEd Maste    size_t srcsz, int byteswap)
7452de3b87aSKai Wang{
7462de3b87aSKai Wang	return (_libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
7472de3b87aSKai Wang		byteswap));
7482de3b87aSKai Wang}
7492de3b87aSKai Wang
7502de3b87aSKai Wangstatic int
751cf781b2eSEd Maste_libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
752cf781b2eSEd Maste    size_t srcsz, int byteswap)
7532de3b87aSKai Wang{
7542de3b87aSKai Wang	size_t sz;
7552de3b87aSKai Wang	uint64_t t64, *bloom64;
7562de3b87aSKai Wang	Elf_GNU_Hash_Header *gh;
7572de3b87aSKai Wang	uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
7582de3b87aSKai Wang	uint32_t *buckets, *chains;
7592de3b87aSKai Wang
7602de3b87aSKai Wang	sz = 4 * sizeof(uint32_t);	/* File header is 4 words long. */
7612de3b87aSKai Wang	if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
7622de3b87aSKai Wang		return (0);
7632de3b87aSKai Wang
7642de3b87aSKai Wang	/* Read in the section header and byteswap if needed. */
7652de3b87aSKai Wang	READ_WORD(src, nbuckets);
7662de3b87aSKai Wang	READ_WORD(src, symndx);
7672de3b87aSKai Wang	READ_WORD(src, maskwords);
7682de3b87aSKai Wang	READ_WORD(src, shift2);
7692de3b87aSKai Wang
7702de3b87aSKai Wang	srcsz -= sz;
7712de3b87aSKai Wang
7722de3b87aSKai Wang	if (byteswap) {
7732de3b87aSKai Wang		SWAP_WORD(nbuckets);
7742de3b87aSKai Wang		SWAP_WORD(symndx);
7752de3b87aSKai Wang		SWAP_WORD(maskwords);
7762de3b87aSKai Wang		SWAP_WORD(shift2);
7772de3b87aSKai Wang	}
7782de3b87aSKai Wang
7792de3b87aSKai Wang	/* Check source buffer and destination buffer sizes. */
7802de3b87aSKai Wang	sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
7812de3b87aSKai Wang	if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
7822de3b87aSKai Wang		return (0);
7832de3b87aSKai Wang
7842de3b87aSKai Wang	gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
7852de3b87aSKai Wang	gh->gh_nbuckets  = nbuckets;
7862de3b87aSKai Wang	gh->gh_symndx    = symndx;
7872de3b87aSKai Wang	gh->gh_maskwords = maskwords;
7882de3b87aSKai Wang	gh->gh_shift2    = shift2;
7892de3b87aSKai Wang
7902de3b87aSKai Wang	dsz -= sizeof(Elf_GNU_Hash_Header);
7912de3b87aSKai Wang	dst += sizeof(Elf_GNU_Hash_Header);
7922de3b87aSKai Wang
7932de3b87aSKai Wang	bloom64 = (uint64_t *) (uintptr_t) dst;
7942de3b87aSKai Wang
7952de3b87aSKai Wang	/* Copy bloom filter data. */
7962de3b87aSKai Wang	for (n = 0; n < maskwords; n++) {
7972de3b87aSKai Wang		READ_XWORD(src, t64);
7982de3b87aSKai Wang		if (byteswap)
7992de3b87aSKai Wang			SWAP_XWORD(t64);
8002de3b87aSKai Wang		bloom64[n] = t64;
8012de3b87aSKai Wang	}
8022de3b87aSKai Wang
8032de3b87aSKai Wang	/* The hash buckets follows the bloom filter. */
8042de3b87aSKai Wang	dst += maskwords * sizeof(uint64_t);
8052de3b87aSKai Wang	buckets = (uint32_t *) (uintptr_t) dst;
8062de3b87aSKai Wang
8072de3b87aSKai Wang	for (n = 0; n < nbuckets; n++) {
8082de3b87aSKai Wang		READ_WORD(src, t32);
8092de3b87aSKai Wang		if (byteswap)
8102de3b87aSKai Wang			SWAP_WORD(t32);
8112de3b87aSKai Wang		buckets[n] = t32;
8122de3b87aSKai Wang	}
8132de3b87aSKai Wang
8142de3b87aSKai Wang	dst += nbuckets * sizeof(uint32_t);
8152de3b87aSKai Wang
8162de3b87aSKai Wang	/* The hash chain follows the hash buckets. */
8172de3b87aSKai Wang	dsz -= sz;
8182de3b87aSKai Wang	srcsz -= sz;
8192de3b87aSKai Wang
8202de3b87aSKai Wang	if (dsz < srcsz)	/* Destination lacks space. */
8212de3b87aSKai Wang		return (0);
8222de3b87aSKai Wang
823d003e0d7SEd Maste	nchains = (uint32_t) (srcsz / sizeof(uint32_t));
8242de3b87aSKai Wang	chains = (uint32_t *) (uintptr_t) dst;
8252de3b87aSKai Wang
8262de3b87aSKai Wang	for (n = 0; n < nchains; n++) {
8272de3b87aSKai Wang		READ_WORD(src, t32);
8282de3b87aSKai Wang		if (byteswap)
8292de3b87aSKai Wang			SWAP_WORD(t32);
8302de3b87aSKai Wang		*chains++ = t32;
8312de3b87aSKai Wang	}
8322de3b87aSKai Wang
8332de3b87aSKai Wang	return (1);
8342de3b87aSKai Wang}
8352de3b87aSKai Wang
8362de3b87aSKai Wangstatic int
837cf781b2eSEd Maste_libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src,
838cf781b2eSEd Maste    size_t srcsz, int byteswap)
8392de3b87aSKai Wang{
8402de3b87aSKai Wang	uint32_t *s32;
8412de3b87aSKai Wang	size_t sz, hdrsz;
8422de3b87aSKai Wang	uint64_t *s64, t64;
8432de3b87aSKai Wang	Elf_GNU_Hash_Header *gh;
8442de3b87aSKai Wang	uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
8452de3b87aSKai Wang
8462de3b87aSKai Wang	hdrsz = 4 * sizeof(uint32_t);	/* Header is 4x32 bits. */
8472de3b87aSKai Wang	if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
8482de3b87aSKai Wang		return (0);
8492de3b87aSKai Wang
8502de3b87aSKai Wang	gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
8512de3b87aSKai Wang
8522de3b87aSKai Wang	t0 = nbuckets = gh->gh_nbuckets;
8532de3b87aSKai Wang	t1 = gh->gh_symndx;
8542de3b87aSKai Wang	t2 = maskwords = gh->gh_maskwords;
8552de3b87aSKai Wang	t3 = gh->gh_shift2;
8562de3b87aSKai Wang
8572de3b87aSKai Wang	src   += sizeof(Elf_GNU_Hash_Header);
8582de3b87aSKai Wang	srcsz -= sizeof(Elf_GNU_Hash_Header);
8592de3b87aSKai Wang	dsz   -= hdrsz;
8602de3b87aSKai Wang
8612de3b87aSKai Wang	sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
8622de3b87aSKai Wang	    sizeof(uint64_t);
8632de3b87aSKai Wang
8642de3b87aSKai Wang	if (srcsz < sz || dsz < sz)
8652de3b87aSKai Wang		return (0);
8662de3b87aSKai Wang
8672de3b87aSKai Wang	/* Write out the header. */
8682de3b87aSKai Wang	if (byteswap) {
8692de3b87aSKai Wang		SWAP_WORD(t0);
8702de3b87aSKai Wang		SWAP_WORD(t1);
8712de3b87aSKai Wang		SWAP_WORD(t2);
8722de3b87aSKai Wang		SWAP_WORD(t3);
8732de3b87aSKai Wang	}
8742de3b87aSKai Wang
8752de3b87aSKai Wang	WRITE_WORD(dst, t0);
8762de3b87aSKai Wang	WRITE_WORD(dst, t1);
8772de3b87aSKai Wang	WRITE_WORD(dst, t2);
8782de3b87aSKai Wang	WRITE_WORD(dst, t3);
8792de3b87aSKai Wang
8802de3b87aSKai Wang	/* Copy the bloom filter and the hash table. */
8812de3b87aSKai Wang	s64 = (uint64_t *) (uintptr_t) src;
8822de3b87aSKai Wang	for (n = 0; n < maskwords; n++) {
8832de3b87aSKai Wang		t64 = *s64++;
8842de3b87aSKai Wang		if (byteswap)
8852de3b87aSKai Wang			SWAP_XWORD(t64);
8862de3b87aSKai Wang		WRITE_WORD64(dst, t64);
8872de3b87aSKai Wang	}
8882de3b87aSKai Wang
8892de3b87aSKai Wang	s32 = (uint32_t *) s64;
8902de3b87aSKai Wang	for (n = 0; n < nbuckets; n++) {
8912de3b87aSKai Wang		t32 = *s32++;
8922de3b87aSKai Wang		if (byteswap)
8932de3b87aSKai Wang			SWAP_WORD(t32);
8942de3b87aSKai Wang		WRITE_WORD(dst, t32);
8952de3b87aSKai Wang	}
8962de3b87aSKai Wang
8972de3b87aSKai Wang	srcsz -= sz;
8982de3b87aSKai Wang	dsz   -= sz;
8992de3b87aSKai Wang
9002de3b87aSKai Wang	/* Copy out the hash chains. */
9012de3b87aSKai Wang	if (dsz < srcsz)
9022de3b87aSKai Wang		return (0);
9032de3b87aSKai Wang
904d003e0d7SEd Maste	nchains = (uint32_t) (srcsz / sizeof(uint32_t));
9052de3b87aSKai Wang	for (n = 0; n < nchains; n++) {
9062de3b87aSKai Wang		t32 = *s32++;
9072de3b87aSKai Wang		if (byteswap)
9082de3b87aSKai Wang			SWAP_WORD(t32);
9092de3b87aSKai Wang		WRITE_WORD(dst, t32);
9102de3b87aSKai Wang	}
9112de3b87aSKai Wang
9122de3b87aSKai Wang	return (1);
9132de3b87aSKai Wang}
9142de3b87aSKai Wang
9152de3b87aSKai Wang/*
9162de3b87aSKai Wang * Elf_Note structures comprise a fixed size header followed by variable
9172de3b87aSKai Wang * length strings.  The fixed size header needs to be byte swapped, but
9182de3b87aSKai Wang * not the strings.
9192de3b87aSKai Wang *
9202de3b87aSKai Wang * Argument `count' denotes the total number of bytes to be converted.
9212de3b87aSKai Wang * The destination buffer needs to be at least `count' bytes in size.
9222de3b87aSKai Wang */
9232de3b87aSKai Wangstatic int
924cf781b2eSEd Maste_libelf_cvt_NOTE_tom(unsigned char *dst, size_t dsz, unsigned char *src,
925cf781b2eSEd Maste    size_t count, int byteswap)
9262de3b87aSKai Wang{
9272de3b87aSKai Wang	uint32_t namesz, descsz, type;
9282de3b87aSKai Wang	Elf_Note *en;
9292de3b87aSKai Wang	size_t sz, hdrsz;
9302de3b87aSKai Wang
9312de3b87aSKai Wang	if (dsz < count)	/* Destination buffer is too small. */
9322de3b87aSKai Wang		return (0);
9332de3b87aSKai Wang
9342de3b87aSKai Wang	hdrsz = 3 * sizeof(uint32_t);
9352de3b87aSKai Wang	if (count < hdrsz)		/* Source too small. */
9362de3b87aSKai Wang		return (0);
9372de3b87aSKai Wang
9382de3b87aSKai Wang	if (!byteswap) {
9392de3b87aSKai Wang		(void) memcpy(dst, src, count);
9402de3b87aSKai Wang		return (1);
9412de3b87aSKai Wang	}
9422de3b87aSKai Wang
9432de3b87aSKai Wang	/* Process all notes in the section. */
9442de3b87aSKai Wang	while (count > hdrsz) {
9452de3b87aSKai Wang		/* Read the note header. */
9462de3b87aSKai Wang		READ_WORD(src, namesz);
9472de3b87aSKai Wang		READ_WORD(src, descsz);
9482de3b87aSKai Wang		READ_WORD(src, type);
9492de3b87aSKai Wang
9502de3b87aSKai Wang		/* Translate. */
9512de3b87aSKai Wang		SWAP_WORD(namesz);
9522de3b87aSKai Wang		SWAP_WORD(descsz);
9532de3b87aSKai Wang		SWAP_WORD(type);
9542de3b87aSKai Wang
9552de3b87aSKai Wang		/* Copy out the translated note header. */
9562de3b87aSKai Wang		en = (Elf_Note *) (uintptr_t) dst;
9572de3b87aSKai Wang		en->n_namesz = namesz;
9582de3b87aSKai Wang		en->n_descsz = descsz;
9592de3b87aSKai Wang		en->n_type = type;
9602de3b87aSKai Wang
9612de3b87aSKai Wang		dsz -= sizeof(Elf_Note);
9622de3b87aSKai Wang		dst += sizeof(Elf_Note);
9632de3b87aSKai Wang		count -= hdrsz;
9642de3b87aSKai Wang
965cf781b2eSEd Maste		ROUNDUP2(namesz, 4U);
966cf781b2eSEd Maste		ROUNDUP2(descsz, 4U);
967ccbdcd03SEd Maste
968ccbdcd03SEd Maste		sz = namesz + descsz;
969ccbdcd03SEd Maste
9702de3b87aSKai Wang		if (count < sz || dsz < sz)	/* Buffers are too small. */
9712de3b87aSKai Wang			return (0);
9722de3b87aSKai Wang
9732de3b87aSKai Wang		(void) memcpy(dst, src, sz);
9742de3b87aSKai Wang
9752de3b87aSKai Wang		src += sz;
9762de3b87aSKai Wang		dst += sz;
9772de3b87aSKai Wang
9782de3b87aSKai Wang		count -= sz;
9792de3b87aSKai Wang		dsz -= sz;
9802de3b87aSKai Wang	}
9812de3b87aSKai Wang
9822de3b87aSKai Wang	return (1);
9832de3b87aSKai Wang}
9842de3b87aSKai Wang
9852de3b87aSKai Wangstatic int
986cf781b2eSEd Maste_libelf_cvt_NOTE_tof(unsigned char *dst, size_t dsz, unsigned char *src,
987cf781b2eSEd Maste    size_t count, int byteswap)
9882de3b87aSKai Wang{
9892de3b87aSKai Wang	uint32_t namesz, descsz, type;
9902de3b87aSKai Wang	Elf_Note *en;
9912de3b87aSKai Wang	size_t sz;
9922de3b87aSKai Wang
9932de3b87aSKai Wang	if (dsz < count)
9942de3b87aSKai Wang		return (0);
9952de3b87aSKai Wang
9962de3b87aSKai Wang	if (!byteswap) {
9972de3b87aSKai Wang		(void) memcpy(dst, src, count);
9982de3b87aSKai Wang		return (1);
9992de3b87aSKai Wang	}
10002de3b87aSKai Wang
10012de3b87aSKai Wang	while (count > sizeof(Elf_Note)) {
10022de3b87aSKai Wang
10032de3b87aSKai Wang		en = (Elf_Note *) (uintptr_t) src;
10042de3b87aSKai Wang		namesz = en->n_namesz;
10052de3b87aSKai Wang		descsz = en->n_descsz;
10062de3b87aSKai Wang		type = en->n_type;
10072de3b87aSKai Wang
1008ccbdcd03SEd Maste		sz = namesz;
1009cf781b2eSEd Maste		ROUNDUP2(sz, 4U);
1010ccbdcd03SEd Maste		sz += descsz;
1011cf781b2eSEd Maste		ROUNDUP2(sz, 4U);
1012ccbdcd03SEd Maste
10132de3b87aSKai Wang		SWAP_WORD(namesz);
10142de3b87aSKai Wang		SWAP_WORD(descsz);
10152de3b87aSKai Wang		SWAP_WORD(type);
10162de3b87aSKai Wang
10172de3b87aSKai Wang		WRITE_WORD(dst, namesz);
10182de3b87aSKai Wang		WRITE_WORD(dst, descsz);
10192de3b87aSKai Wang		WRITE_WORD(dst, type);
10202de3b87aSKai Wang
10212de3b87aSKai Wang		src += sizeof(Elf_Note);
1022a87342e8SEd Maste		count -= sizeof(Elf_Note);
10232de3b87aSKai Wang
10242de3b87aSKai Wang		if (count < sz)
10252f7242edSEd Maste			return (0);
10262de3b87aSKai Wang
10272de3b87aSKai Wang		(void) memcpy(dst, src, sz);
10282de3b87aSKai Wang
10292de3b87aSKai Wang		src += sz;
10302de3b87aSKai Wang		dst += sz;
10312de3b87aSKai Wang		count -= sz;
10322de3b87aSKai Wang	}
10332de3b87aSKai Wang
10342de3b87aSKai Wang	return (1);
10352de3b87aSKai Wang}
10362de3b87aSKai Wang
10372de3b87aSKai Wangstruct converters {
1038cf781b2eSEd Maste	int	(*tof32)(unsigned char *dst, size_t dsz, unsigned char *src,
1039cf781b2eSEd Maste		    size_t cnt, int byteswap);
1040cf781b2eSEd Maste	int	(*tom32)(unsigned char *dst, size_t dsz, unsigned char *src,
1041cf781b2eSEd Maste		    size_t cnt, int byteswap);
1042cf781b2eSEd Maste	int	(*tof64)(unsigned char *dst, size_t dsz, unsigned char *src,
1043cf781b2eSEd Maste		    size_t cnt, int byteswap);
1044cf781b2eSEd Maste	int	(*tom64)(unsigned char *dst, size_t dsz, unsigned char *src,
1045cf781b2eSEd Maste		    size_t cnt, int byteswap);
10462de3b87aSKai Wang};
10472de3b87aSKai Wang
10482de3b87aSKai Wang
10492de3b87aSKai Wangstatic struct converters cvt[ELF_T_NUM] = {
10502de3b87aSKai Wang	/*[*/
10512de3b87aSKai WangCONVERTER_NAMES(ELF_TYPE_LIST)
10522de3b87aSKai Wang	/*]*/
10532de3b87aSKai Wang
10542de3b87aSKai Wang	/*
10552de3b87aSKai Wang	 * Types that need hand-coded converters follow.
10562de3b87aSKai Wang	 */
10572de3b87aSKai Wang
10582de3b87aSKai Wang	[ELF_T_BYTE] = {
10592de3b87aSKai Wang		.tof32 = _libelf_cvt_BYTE_tox,
10602de3b87aSKai Wang		.tom32 = _libelf_cvt_BYTE_tox,
10612de3b87aSKai Wang		.tof64 = _libelf_cvt_BYTE_tox,
10622de3b87aSKai Wang		.tom64 = _libelf_cvt_BYTE_tox
10632de3b87aSKai Wang	},
10642de3b87aSKai Wang
10652de3b87aSKai Wang	[ELF_T_NOTE] = {
10662de3b87aSKai Wang		.tof32 = _libelf_cvt_NOTE_tof,
10672de3b87aSKai Wang		.tom32 = _libelf_cvt_NOTE_tom,
10682de3b87aSKai Wang		.tof64 = _libelf_cvt_NOTE_tof,
10692de3b87aSKai Wang		.tom64 = _libelf_cvt_NOTE_tom
10702de3b87aSKai Wang	}
10712de3b87aSKai Wang};
10722de3b87aSKai Wang
1073ae500c1fSEd Maste/*
1074ae500c1fSEd Maste * Return a translator function for the specified ELF section type, conversion
1075ae500c1fSEd Maste * direction, ELF class and ELF machine.
1076ae500c1fSEd Maste */
1077ae500c1fSEd Maste_libelf_translator_function *
1078ae500c1fSEd Maste_libelf_get_translator(Elf_Type t, int direction, int elfclass, int elfmachine)
10792de3b87aSKai Wang{
10802de3b87aSKai Wang	assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
10812de3b87aSKai Wang	assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
1082d003e0d7SEd Maste	assert(t >= ELF_T_FIRST && t <= ELF_T_LAST);
10832de3b87aSKai Wang
1084ae500c1fSEd Maste	/* TODO: Handle MIPS64 REL{,A} sections (ticket #559). */
1085ae500c1fSEd Maste	(void) elfmachine;
1086ae500c1fSEd Maste
10872de3b87aSKai Wang	return ((elfclass == ELFCLASS32) ?
10882de3b87aSKai Wang	    (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
10892de3b87aSKai Wang	    (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
10902de3b87aSKai Wang}
1091