summaryrefslogtreecommitdiff
path: root/lib/libelf/libelf_convert.m4
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2019-02-01 05:27:39 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2019-02-01 05:27:39 +0000
commit666732e8bdff49716cf57ec971f0f550af9876fd (patch)
tree94ce092078bb1939af462fe0673fd3493153667b /lib/libelf/libelf_convert.m4
parent209bd1f4d835892e16bcacd34d5a67e7d8c1c647 (diff)
add libelf from elftoolchain r3669
A 2 clause BSD licensed implementation of the SVR4 ELF API also implemented by mr511.de libelf (devel/libelf in ports) and elfutils. It is being added to base to allow Mesa to use it in future. shlib major is higher than devel/libelf and pkg-config version is 0.8.2 to pass a glib2 configure test so this can replace the use of devel/libelf in ports.
Diffstat (limited to 'lib/libelf/libelf_convert.m4')
-rw-r--r--lib/libelf/libelf_convert.m41096
1 files changed, 1096 insertions, 0 deletions
diff --git a/lib/libelf/libelf_convert.m4 b/lib/libelf/libelf_convert.m4
new file mode 100644
index 00000000000..a063076bb07
--- /dev/null
+++ b/lib/libelf/libelf_convert.m4
@@ -0,0 +1,1096 @@
+/*-
+ * Copyright (c) 2006-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <libelf.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "_libelf.h"
+
+ELFTC_VCSID("$Id: libelf_convert.m4,v 1.1 2019/02/01 05:27:38 jsg Exp $");
+
+/* WARNING: GENERATED FROM __file__. */
+
+divert(-1)
+
+# Generate conversion routines for converting between in-memory and
+# file representations of Elf data structures.
+#
+# These conversions use the type information defined in `elf_types.m4'.
+
+include(SRCDIR`/elf_types.m4')
+
+# For the purposes of generating conversion code, ELF types may be
+# classified according to the following characteristics:
+#
+# 1. Whether the ELF type can be directly mapped to an integral C
+# language type. For example, the ELF_T_WORD type maps directly to
+# a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type.
+#
+# 2. Whether the type has word size dependent variants. For example,
+# ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr,
+# and the ELF_T_ADDR and ELF_T_OFF types have integral C types that
+# can be 32- or 64- bit wide.
+#
+# 3. Whether the ELF types has a fixed representation or not. For
+# example, the ELF_T_SYM type has a fixed size file representation,
+# some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size
+# representation.
+#
+# We use m4 macros to generate conversion code for ELF types that have
+# a fixed size representation. Conversion functions for the remaining
+# types are coded by hand.
+#
+#* Handling File and Memory Representations
+#
+# `In-memory' representations of an Elf data structure use natural
+# alignments and native byte ordering. This allows pointer arithmetic
+# and casting to work as expected. On the other hand, the `file'
+# representation of an ELF data structure could possibly be packed
+# tighter than its `in-memory' representation, and could be of a
+# differing byte order. Reading ELF objects that are members of `ar'
+# archives present an additional complication: `ar' pads file data to
+# even addresses, so file data structures in an archive member
+# residing inside an `ar' archive could be at misaligned memory
+# addresses when brought into memory.
+#
+# In summary, casting the `char *' pointers that point to memory
+# representations (i.e., source pointers for the *_tof() functions and
+# the destination pointers for the *_tom() functions), is safe, as
+# these pointers should be correctly aligned for the memory type
+# already. However, pointers to file representations have to be
+# treated as being potentially unaligned and no casting can be done.
+
+# NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE
+define(`NOCVT',`define(`NOCVT_'$1,1)')
+
+# NOFUNC(TYPE) -- Do not generate a conversion function for TYPE
+define(`NOFUNC',`define(`NOFUNC_'$1,1)')
+
+# IGNORE(TYPE) -- Completely ignore the type.
+define(`IGNORE',`NOCVT($1)NOFUNC($1)')
+
+# Mark ELF types that should not be processed by the M4 macros below.
+
+# Types for which we use functions with non-standard names.
+IGNORE(`BYTE') # Uses a wrapper around memcpy().
+IGNORE(`NOTE') # Not a fixed size type.
+
+# Types for which we supply hand-coded functions.
+NOFUNC(`GNUHASH') # A type with complex internal structure.
+NOFUNC(`VDEF') # See MAKE_VERSION_CONVERTERS below.
+NOFUNC(`VNEED') # ..
+
+# Unimplemented types.
+IGNORE(`MOVEP')
+
+# ELF types that don't exist in a 32-bit world.
+NOFUNC(`XWORD32')
+NOFUNC(`SXWORD32')
+
+# `Primitive' ELF types are those that are an alias for an integral
+# type. As they have no internal structure, they can be copied using
+# a `memcpy()', and byteswapped in straightforward way.
+#
+# Mark all ELF types that directly map to integral C types.
+define(`PRIM_ADDR', 1)
+define(`PRIM_BYTE', 1)
+define(`PRIM_HALF', 1)
+define(`PRIM_LWORD', 1)
+define(`PRIM_OFF', 1)
+define(`PRIM_SWORD', 1)
+define(`PRIM_SXWORD', 1)
+define(`PRIM_WORD', 1)
+define(`PRIM_XWORD', 1)
+
+# Note the primitive types that are size-dependent.
+define(`SIZEDEP_ADDR', 1)
+define(`SIZEDEP_OFF', 1)
+
+# Generate conversion functions for primitive types.
+#
+# Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE)
+# `$1': Name of the ELF type.
+# `$2': C structure name suffix.
+# `$3': ELF class specifier for types, one of [`32', `64'].
+# `$4': Additional ELF class specifier, one of [`', `32', `64'].
+#
+# Generates a pair of conversion functions.
+define(`MAKEPRIMFUNCS',`
+static int
+_libelf_cvt_$1$4_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src;
+ size_t c;
+
+ (void) dsz;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*s));
+ return (1);
+ }
+
+ for (c = 0; c < count; c++) {
+ t = *s++;
+ SWAP_$1$4(t);
+ WRITE_$1$4(dst,t);
+ }
+
+ return (1);
+}
+
+static int
+_libelf_cvt_$1$4_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst;
+ size_t c;
+
+ if (dsz < count * sizeof(Elf$3_$2))
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*d));
+ return (1);
+ }
+
+ for (c = 0; c < count; c++) {
+ READ_$1$4(src,t);
+ SWAP_$1$4(t);
+ *d++ = t;
+ }
+
+ return (1);
+}
+')
+
+#
+# Handling composite ELF types
+#
+
+# SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field.
+define(`SWAP_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `SWAP_$2'SZ()`(t.$1);
+ ',
+ `SWAP_$2(t.$1);
+ ')')
+
+# SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition.
+define(`SWAP_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
+
+# SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure.
+define(`SWAP_STRUCT',
+ `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
+ SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+# WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field.
+define(`WRITE_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `WRITE_$2'SZ()`(dst,t.$1);
+ ',
+ `WRITE_$2(dst,t.$1);
+ ')')
+
+# WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
+define(`WRITE_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
+
+# WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure.
+define(`WRITE_STRUCT',
+ `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
+ WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+# READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field.
+define(`READ_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `READ_$2'SZ()`(s,t.$1);
+ ',
+ `READ_$2(s,t.$1);
+ ')')
+
+# READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
+define(`READ_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `READ_FIELD($1)READ_MEMBERS(shift($@))')')
+
+# READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure.
+define(`READ_STRUCT',
+ `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
+ READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+
+# MAKECOMPFUNCS -- Generate converters for composite ELF structures.
+#
+# When converting data to file representation, the source pointer will
+# be naturally aligned for a data structure's in-memory
+# representation. When converting data to memory, the destination
+# pointer will be similarly aligned.
+#
+# For in-place conversions, when converting to file representations,
+# the source buffer is large enough to hold `file' data. When
+# converting from file to memory, we need to be careful to work
+# `backwards', to avoid overwriting unconverted data.
+#
+# Macro use:
+# `$1': Name of the ELF type.
+# `$2': C structure name suffix.
+# `$3': ELF class specifier, one of [`', `32', `64']
+define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',`
+static int
+_libelf_cvt_$1$3_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$3_$2 t, *s;
+ size_t c;
+
+ (void) dsz;
+
+ s = (Elf$3_$2 *) (uintptr_t) src;
+ for (c = 0; c < count; c++) {
+ t = *s++;
+ if (byteswap) {
+ SWAP_STRUCT($2,$3)
+ }
+ WRITE_STRUCT($2,$3)
+ }
+
+ return (1);
+}
+
+static int
+_libelf_cvt_$1$3_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$3_$2 t, *d;
+ unsigned char *s,*s0;
+ size_t fsz;
+
+ fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT);
+ d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
+ s0 = src + (count - 1) * fsz;
+
+ if (dsz < count * sizeof(Elf$3_$2))
+ return (0);
+
+ while (count--) {
+ s = s0;
+ READ_STRUCT($2,$3)
+ if (byteswap) {
+ SWAP_STRUCT($2,$3)
+ }
+ *d-- = t; s0 -= fsz;
+ }
+
+ return (1);
+}
+')')
+
+# MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE)
+#
+# Make type convertor functions from the type definition
+# of the ELF type:
+# - Skip convertors marked as `NOFUNC'.
+# - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate.
+define(`MAKE_TYPE_CONVERTER',
+ `ifdef(`NOFUNC_'$1,`',
+ `ifdef(`PRIM_'$1,
+ `ifdef(`SIZEDEP_'$1,
+ `MAKEPRIMFUNCS($1,$2,32,32)dnl
+ MAKEPRIMFUNCS($1,$2,64,64)',
+ `MAKEPRIMFUNCS($1,$2,64)')',
+ `MAKECOMPFUNCS($1,$2,32)dnl
+ MAKECOMPFUNCS($1,$2,64)')')')
+
+# MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions.
+define(`MAKE_TYPE_CONVERTERS',
+ `ifelse($#,1,`',
+ `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
+
+
+#
+# Macros to generate entries for the table of convertors.
+#
+
+# CONV(ELFTYPE,SIZE,DIRECTION)
+#
+# Generate the name of a convertor function.
+define(`CONV',
+ `ifdef(`NOFUNC_'$1$2,
+ `.$3$2 = NULL',
+ `ifdef(`PRIM_'$1,
+ `ifdef(`SIZEDEP_'$1,
+ `.$3$2 = _libelf_cvt_$1$2_$3',
+ `.$3$2 = _libelf_cvt_$1_$3')',
+ `.$3$2 = _libelf_cvt_$1$2_$3')')')
+
+# CONVERTER_NAME(ELFTYPE)
+#
+# Generate the contents of one `struct cvt' instance.
+define(`CONVERTER_NAME',
+ `ifdef(`NOCVT_'$1,`',
+ ` [ELF_T_$1] = {
+ CONV($1,32,tof),
+ CONV($1,32,tom),
+ CONV($1,64,tof),
+ CONV($1,64,tom)
+ },
+
+')')
+
+# CONVERTER_NAMES(ELFTYPELIST)
+#
+# Generate the `struct cvt[]' array.
+define(`CONVERTER_NAMES',
+ `ifelse($#,1,`',
+ `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
+
+#
+# Handling ELF version sections.
+#
+
+# _FSZ(FIELD,BASETYPE) - return the file size for a field.
+define(`_FSZ',
+ `ifelse($2,`HALF',2,
+ $2,`WORD',4)')
+
+# FSZ(STRUCT) - determine the file size of a structure.
+define(`FSZ',
+ `ifelse($#,1,0,
+ `eval(_FSZ($1) + FSZ(shift($@)))')')
+
+# MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion
+# functions for versioning structures.
+define(`MAKE_VERSION_CONVERTERS',
+ `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32)
+ MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)')
+
+# MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a
+# conversion function.
+define(`MAKE_VERSION_CONVERTER',`
+static int
+_libelf_cvt_$1$5_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$5_$2 t;
+ Elf$5_$3 a;
+ const size_t verfsz = FSZ(Elf$5_$2_DEF);
+ const size_t auxfsz = FSZ(Elf$5_$3_DEF);
+ const size_t vermsz = sizeof(Elf$5_$2);
+ const size_t auxmsz = sizeof(Elf$5_$3);
+ unsigned char * const dstend = dst + dsz;
+ unsigned char * const srcend = src + count;
+ unsigned char *dtmp, *dstaux, *srcaux;
+ Elf$5_Word aux, anext, cnt, vnext;
+
+ for (dtmp = dst, vnext = ~0U;
+ vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend;
+ dtmp += vnext, src += vnext) {
+
+ /* Read in an Elf$5_$2 structure. */
+ t = *((Elf$5_$2 *) (uintptr_t) src);
+
+ aux = t.$4_aux;
+ cnt = t.$4_cnt;
+ vnext = t.$4_next;
+
+ if (byteswap) {
+ SWAP_STRUCT($2, $5)
+ }
+
+ dst = dtmp;
+ WRITE_STRUCT($2, $5)
+
+ if (aux < verfsz)
+ return (0);
+
+ /* Process AUX entries. */
+ for (anext = ~0U, dstaux = dtmp + aux, srcaux = src + aux;
+ cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend &&
+ srcaux + auxmsz <= srcend;
+ dstaux += anext, srcaux += anext, cnt--) {
+
+ /* Read in an Elf$5_$3 structure. */
+ a = *((Elf$5_$3 *) (uintptr_t) srcaux);
+ anext = a.$4a_next;
+
+ if (byteswap) {
+ pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
+ }
+
+ dst = dstaux;
+ pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t')
+ }
+
+ if (anext || cnt)
+ return (0);
+ }
+
+ if (vnext)
+ return (0);
+
+ return (1);
+}
+
+static int
+_libelf_cvt_$1$5_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ Elf$5_$2 t, *dp;
+ Elf$5_$3 a, *ap;
+ const size_t verfsz = FSZ(Elf$5_$2_DEF);
+ const size_t auxfsz = FSZ(Elf$5_$3_DEF);
+ const size_t vermsz = sizeof(Elf$5_$2);
+ const size_t auxmsz = sizeof(Elf$5_$3);
+ unsigned char * const dstend = dst + dsz;
+ unsigned char * const srcend = src + count;
+ unsigned char *dstaux, *s, *srcaux, *stmp;
+ Elf$5_Word aux, anext, cnt, vnext;
+
+ for (stmp = src, vnext = ~0U;
+ vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
+ stmp += vnext, dst += vnext) {
+
+ /* Read in a $1 structure. */
+ s = stmp;
+ READ_STRUCT($2, $5)
+ if (byteswap) {
+ SWAP_STRUCT($2, $5)
+ }
+
+ dp = (Elf$5_$2 *) (uintptr_t) dst;
+ *dp = t;
+
+ aux = t.$4_aux;
+ cnt = t.$4_cnt;
+ vnext = t.$4_next;
+
+ if (aux < vermsz)
+ return (0);
+
+ /* Process AUX entries. */
+ for (anext = ~0U, dstaux = dst + aux, srcaux = stmp + aux;
+ cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend &&
+ srcaux + auxfsz <= srcend;
+ dstaux += anext, srcaux += anext, cnt--) {
+
+ s = srcaux;
+ pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t')
+
+ if (byteswap) {
+ pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
+ }
+
+ anext = a.$4a_next;
+
+ ap = ((Elf$5_$3 *) (uintptr_t) dstaux);
+ *ap = a;
+ }
+
+ if (anext || cnt)
+ return (0);
+ }
+
+ if (vnext)
+ return (0);
+
+ return (1);
+}')
+
+divert(0)
+
+/*
+ * C macros to byte swap integral quantities.
+ */
+
+#define SWAP_BYTE(X) do { (void) (X); } while (0)
+#define SWAP_IDENT(X) do { (void) (X); } while (0)
+#define SWAP_HALF(X) do { \
+ uint16_t _x = (uint16_t) (X); \
+ uint32_t _t = _x & 0xFFU; \
+ _t <<= 8U; _x >>= 8U; _t |= _x & 0xFFU; \
+ (X) = (uint16_t) _t; \
+ } while (0)
+#define _SWAP_WORD(X, T) do { \
+ uint32_t _x = (uint32_t) (X); \
+ uint32_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = (T) _t; \
+ } while (0)
+#define SWAP_ADDR32(X) _SWAP_WORD(X, Elf32_Addr)
+#define SWAP_OFF32(X) _SWAP_WORD(X, Elf32_Off)
+#define SWAP_SWORD(X) _SWAP_WORD(X, Elf32_Sword)
+#define SWAP_WORD(X) _SWAP_WORD(X, Elf32_Word)
+#define _SWAP_WORD64(X, T) do { \
+ uint64_t _x = (uint64_t) (X); \
+ uint64_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = (T) _t; \
+ } while (0)
+#define SWAP_ADDR64(X) _SWAP_WORD64(X, Elf64_Addr)
+#define SWAP_LWORD(X) _SWAP_WORD64(X, Elf64_Lword)
+#define SWAP_OFF64(X) _SWAP_WORD64(X, Elf64_Off)
+#define SWAP_SXWORD(X) _SWAP_WORD64(X, Elf64_Sxword)
+#define SWAP_XWORD(X) _SWAP_WORD64(X, Elf64_Xword)
+
+/*
+ * C macros to write out various integral values.
+ *
+ * Note:
+ * - The destination pointer could be unaligned.
+ * - Values are written out in native byte order.
+ * - The destination pointer is incremented after the write.
+ */
+#define WRITE_BYTE(P,X) do { \
+ unsigned char *const _p = (unsigned char *) (P); \
+ _p[0] = (unsigned char) (X); \
+ (P) = _p + 1; \
+ } while (0)
+#define WRITE_HALF(P,X) do { \
+ uint16_t _t = (X); \
+ unsigned char *const _p = (unsigned char *) (P); \
+ const unsigned char *const _q = (unsigned char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ (P) = _p + 2; \
+ } while (0)
+#define WRITE_WORD(P,X) do { \
+ uint32_t _t = (uint32_t) (X); \
+ unsigned char *const _p = (unsigned char *) (P); \
+ const unsigned char *const _q = (unsigned char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ _p[2] = _q[2]; \
+ _p[3] = _q[3]; \
+ (P) = _p + 4; \
+ } while (0)
+#define WRITE_ADDR32(P,X) WRITE_WORD(P,X)
+#define WRITE_OFF32(P,X) WRITE_WORD(P,X)
+#define WRITE_SWORD(P,X) WRITE_WORD(P,X)
+#define WRITE_WORD64(P,X) do { \
+ uint64_t _t = (uint64_t) (X); \
+ unsigned char *const _p = (unsigned char *) (P); \
+ const unsigned char *const _q = (unsigned char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ _p[2] = _q[2]; \
+ _p[3] = _q[3]; \
+ _p[4] = _q[4]; \
+ _p[5] = _q[5]; \
+ _p[6] = _q[6]; \
+ _p[7] = _q[7]; \
+ (P) = _p + 8; \
+ } while (0)
+#define WRITE_ADDR64(P,X) WRITE_WORD64(P,X)
+#define WRITE_LWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_OFF64(P,X) WRITE_WORD64(P,X)
+#define WRITE_SXWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_XWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_IDENT(P,X) do { \
+ (void) memcpy((P), (X), sizeof((X))); \
+ (P) = (P) + EI_NIDENT; \
+ } while (0)
+
+/*
+ * C macros to read in various integral values.
+ *
+ * Note:
+ * - The source pointer could be unaligned.
+ * - Values are read in native byte order.
+ * - The source pointer is incremented appropriately.
+ */
+
+#define READ_BYTE(P,X) do { \
+ const unsigned char *const _p = \
+ (const unsigned char *) (P); \
+ (X) = _p[0]; \
+ (P) = (P) + 1; \
+ } while (0)
+#define READ_HALF(P,X) do { \
+ uint16_t _t; \
+ unsigned char *const _q = (unsigned char *) &_t; \
+ const unsigned char *const _p = \
+ (const unsigned char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ (P) = (P) + 2; \
+ (X) = _t; \
+ } while (0)
+#define _READ_WORD(P,X,T) do { \
+ uint32_t _t; \
+ unsigned char *const _q = (unsigned char *) &_t; \
+ const unsigned char *const _p = \
+ (const unsigned char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ _q[2] = _p[2]; \
+ _q[3] = _p[3]; \
+ (P) = (P) + 4; \
+ (X) = (T) _t; \
+ } while (0)
+#define READ_ADDR32(P,X) _READ_WORD(P, X, Elf32_Addr)
+#define READ_OFF32(P,X) _READ_WORD(P, X, Elf32_Off)
+#define READ_SWORD(P,X) _READ_WORD(P, X, Elf32_Sword)
+#define READ_WORD(P,X) _READ_WORD(P, X, Elf32_Word)
+#define _READ_WORD64(P,X,T) do { \
+ uint64_t _t; \
+ unsigned char *const _q = (unsigned char *) &_t; \
+ const unsigned char *const _p = \
+ (const unsigned char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ _q[2] = _p[2]; \
+ _q[3] = _p[3]; \
+ _q[4] = _p[4]; \
+ _q[5] = _p[5]; \
+ _q[6] = _p[6]; \
+ _q[7] = _p[7]; \
+ (P) = (P) + 8; \
+ (X) = (T) _t; \
+ } while (0)
+#define READ_ADDR64(P,X) _READ_WORD64(P, X, Elf64_Addr)
+#define READ_LWORD(P,X) _READ_WORD64(P, X, Elf64_Lword)
+#define READ_OFF64(P,X) _READ_WORD64(P, X, Elf64_Off)
+#define READ_SXWORD(P,X) _READ_WORD64(P, X, Elf64_Sxword)
+#define READ_XWORD(P,X) _READ_WORD64(P, X, Elf64_Xword)
+#define READ_IDENT(P,X) do { \
+ (void) memcpy((X), (P), sizeof((X))); \
+ (P) = (P) + EI_NIDENT; \
+ } while (0)
+
+#define ROUNDUP2(V,N) (V) = ((((V) + (N) - 1)) & ~((N) - 1))
+
+/*[*/
+MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
+MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd)
+MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn)
+/*]*/
+
+/*
+ * Sections of type ELF_T_BYTE are never byteswapped, consequently a
+ * simple memcpy suffices for both directions of conversion.
+ */
+
+static int
+_libelf_cvt_BYTE_tox(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ (void) byteswap;
+ if (dsz < count)
+ return (0);
+ if (dst != src)
+ (void) memcpy(dst, src, count);
+ return (1);
+}
+
+/*
+ * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
+ * words. Bloom filter data comes next, followed by hash buckets and the
+ * hash chain.
+ *
+ * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
+ * wide on ELFCLASS32 objects. The other objects in this section are 32
+ * bits wide.
+ *
+ * Argument `srcsz' denotes the number of bytes to be converted. In the
+ * 32-bit case we need to translate `srcsz' to a count of 32-bit words.
+ */
+
+static int
+_libelf_cvt_GNUHASH32_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t srcsz, int byteswap)
+{
+ return (_libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
+ byteswap));
+}
+
+static int
+_libelf_cvt_GNUHASH32_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t srcsz, int byteswap)
+{
+ return (_libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
+ byteswap));
+}
+
+static int
+_libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t srcsz, int byteswap)
+{
+ size_t sz;
+ uint64_t t64, *bloom64;
+ Elf_GNU_Hash_Header *gh;
+ uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
+ uint32_t *buckets, *chains;
+
+ sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */
+ if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
+ return (0);
+
+ /* Read in the section header and byteswap if needed. */
+ READ_WORD(src, nbuckets);
+ READ_WORD(src, symndx);
+ READ_WORD(src, maskwords);
+ READ_WORD(src, shift2);
+
+ srcsz -= sz;
+
+ if (byteswap) {
+ SWAP_WORD(nbuckets);
+ SWAP_WORD(symndx);
+ SWAP_WORD(maskwords);
+ SWAP_WORD(shift2);
+ }
+
+ /* Check source buffer and destination buffer sizes. */
+ sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
+ if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
+ return (0);
+
+ gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
+ gh->gh_nbuckets = nbuckets;
+ gh->gh_symndx = symndx;
+ gh->gh_maskwords = maskwords;
+ gh->gh_shift2 = shift2;
+
+ dsz -= sizeof(Elf_GNU_Hash_Header);
+ dst += sizeof(Elf_GNU_Hash_Header);
+
+ bloom64 = (uint64_t *) (uintptr_t) dst;
+
+ /* Copy bloom filter data. */
+ for (n = 0; n < maskwords; n++) {
+ READ_XWORD(src, t64);
+ if (byteswap)
+ SWAP_XWORD(t64);
+ bloom64[n] = t64;
+ }
+
+ /* The hash buckets follows the bloom filter. */
+ dst += maskwords * sizeof(uint64_t);
+ buckets = (uint32_t *) (uintptr_t) dst;
+
+ for (n = 0; n < nbuckets; n++) {
+ READ_WORD(src, t32);
+ if (byteswap)
+ SWAP_WORD(t32);
+ buckets[n] = t32;
+ }
+
+ dst += nbuckets * sizeof(uint32_t);
+
+ /* The hash chain follows the hash buckets. */
+ dsz -= sz;
+ srcsz -= sz;
+
+ if (dsz < srcsz) /* Destination lacks space. */
+ return (0);
+
+ nchains = srcsz / sizeof(uint32_t);
+ chains = (uint32_t *) (uintptr_t) dst;
+
+ for (n = 0; n < nchains; n++) {
+ READ_WORD(src, t32);
+ if (byteswap)
+ SWAP_WORD(t32);
+ *chains++ = t32;
+ }
+
+ return (1);
+}
+
+static int
+_libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t srcsz, int byteswap)
+{
+ uint32_t *s32;
+ size_t sz, hdrsz;
+ uint64_t *s64, t64;
+ Elf_GNU_Hash_Header *gh;
+ uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
+
+ hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */
+ if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
+ return (0);
+
+ gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
+
+ t0 = nbuckets = gh->gh_nbuckets;
+ t1 = gh->gh_symndx;
+ t2 = maskwords = gh->gh_maskwords;
+ t3 = gh->gh_shift2;
+
+ src += sizeof(Elf_GNU_Hash_Header);
+ srcsz -= sizeof(Elf_GNU_Hash_Header);
+ dsz -= hdrsz;
+
+ sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
+ sizeof(uint64_t);
+
+ if (srcsz < sz || dsz < sz)
+ return (0);
+
+ /* Write out the header. */
+ if (byteswap) {
+ SWAP_WORD(t0);
+ SWAP_WORD(t1);
+ SWAP_WORD(t2);
+ SWAP_WORD(t3);
+ }
+
+ WRITE_WORD(dst, t0);
+ WRITE_WORD(dst, t1);
+ WRITE_WORD(dst, t2);
+ WRITE_WORD(dst, t3);
+
+ /* Copy the bloom filter and the hash table. */
+ s64 = (uint64_t *) (uintptr_t) src;
+ for (n = 0; n < maskwords; n++) {
+ t64 = *s64++;
+ if (byteswap)
+ SWAP_XWORD(t64);
+ WRITE_WORD64(dst, t64);
+ }
+
+ s32 = (uint32_t *) s64;
+ for (n = 0; n < nbuckets; n++) {
+ t32 = *s32++;
+ if (byteswap)
+ SWAP_WORD(t32);
+ WRITE_WORD(dst, t32);
+ }
+
+ srcsz -= sz;
+ dsz -= sz;
+
+ /* Copy out the hash chains. */
+ if (dsz < srcsz)
+ return (0);
+
+ nchains = srcsz / sizeof(uint32_t);
+ for (n = 0; n < nchains; n++) {
+ t32 = *s32++;
+ if (byteswap)
+ SWAP_WORD(t32);
+ WRITE_WORD(dst, t32);
+ }
+
+ return (1);
+}
+
+/*
+ * Elf_Note structures comprise a fixed size header followed by variable
+ * length strings. The fixed size header needs to be byte swapped, but
+ * not the strings.
+ *
+ * Argument `count' denotes the total number of bytes to be converted.
+ * The destination buffer needs to be at least `count' bytes in size.
+ */
+static int
+_libelf_cvt_NOTE_tom(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz, hdrsz;
+
+ if (dsz < count) /* Destination buffer is too small. */
+ return (0);
+
+ hdrsz = 3 * sizeof(uint32_t);
+ if (count < hdrsz) /* Source too small. */
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return (1);
+ }
+
+ /* Process all notes in the section. */
+ while (count > hdrsz) {
+ /* Read the note header. */
+ READ_WORD(src, namesz);
+ READ_WORD(src, descsz);
+ READ_WORD(src, type);
+
+ /* Translate. */
+ SWAP_WORD(namesz);
+ SWAP_WORD(descsz);
+ SWAP_WORD(type);
+
+ /* Copy out the translated note header. */
+ en = (Elf_Note *) (uintptr_t) dst;
+ en->namesz = namesz;
+ en->descsz = descsz;
+ en->type = type;
+
+ dsz -= sizeof(Elf_Note);
+ dst += sizeof(Elf_Note);
+ count -= hdrsz;
+
+ ROUNDUP2(namesz, 4U);
+ ROUNDUP2(descsz, 4U);
+
+ sz = namesz + descsz;
+
+ if (count < sz || dsz < sz) /* Buffers are too small. */
+ return (0);
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+
+ count -= sz;
+ dsz -= sz;
+ }
+
+ return (1);
+}
+
+static int
+_libelf_cvt_NOTE_tof(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t count, int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz;
+
+ if (dsz < count)
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return (1);
+ }
+
+ while (count > sizeof(Elf_Note)) {
+
+ en = (Elf_Note *) (uintptr_t) src;
+ namesz = en->namesz;
+ descsz = en->descsz;
+ type = en->type;
+
+ sz = namesz;
+ ROUNDUP2(sz, 4U);
+ sz += descsz;
+ ROUNDUP2(sz, 4U);
+
+ SWAP_WORD(namesz);
+ SWAP_WORD(descsz);
+ SWAP_WORD(type);
+
+ WRITE_WORD(dst, namesz);
+ WRITE_WORD(dst, descsz);
+ WRITE_WORD(dst, type);
+
+ src += sizeof(Elf_Note);
+ count -= sizeof(Elf_Note);
+
+ if (count < sz)
+ sz = count;
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+ count -= sz;
+ }
+
+ return (1);
+}
+
+struct converters {
+ int (*tof32)(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t cnt, int byteswap);
+ int (*tom32)(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t cnt, int byteswap);
+ int (*tof64)(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t cnt, int byteswap);
+ int (*tom64)(unsigned char *dst, size_t dsz, unsigned char *src,
+ size_t cnt, int byteswap);
+};
+
+
+static struct converters cvt[ELF_T_NUM] = {
+ /*[*/
+CONVERTER_NAMES(ELF_TYPE_LIST)
+ /*]*/
+
+ /*
+ * Types that need hand-coded converters follow.
+ */
+
+ [ELF_T_BYTE] = {
+ .tof32 = _libelf_cvt_BYTE_tox,
+ .tom32 = _libelf_cvt_BYTE_tox,
+ .tof64 = _libelf_cvt_BYTE_tox,
+ .tom64 = _libelf_cvt_BYTE_tox
+ },
+
+ [ELF_T_NOTE] = {
+ .tof32 = _libelf_cvt_NOTE_tof,
+ .tom32 = _libelf_cvt_NOTE_tom,
+ .tof64 = _libelf_cvt_NOTE_tof,
+ .tom64 = _libelf_cvt_NOTE_tom
+ }
+};
+
+/*
+ * Return a translator function for the specified ELF section type, conversion
+ * direction, ELF class and ELF machine.
+ */
+_libelf_translator_function *
+_libelf_get_translator(Elf_Type t, int direction, int elfclass, int elfmachine)
+{
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+ assert(elfmachine >= EM_NONE && elfmachine < EM__LAST__);
+ assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
+
+ if (t >= ELF_T_NUM ||
+ (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) ||
+ (direction != ELF_TOFILE && direction != ELF_TOMEMORY))
+ return (NULL);
+
+ /* TODO: Handle MIPS64 REL{,A} sections (ticket #559). */
+ (void) elfmachine;
+
+ return ((elfclass == ELFCLASS32) ?
+ (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
+ (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
+}