summaryrefslogtreecommitdiff
path: root/ext/libelf/libelf_convert.m4
diff options
context:
space:
mode:
Diffstat (limited to 'ext/libelf/libelf_convert.m4')
-rw-r--r--ext/libelf/libelf_convert.m4657
1 files changed, 657 insertions, 0 deletions
diff --git a/ext/libelf/libelf_convert.m4 b/ext/libelf/libelf_convert.m4
new file mode 100644
index 000000000..1f21dbe4c
--- /dev/null
+++ b/ext/libelf/libelf_convert.m4
@@ -0,0 +1,657 @@
+/*-
+ * Copyright (c) 2006 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 <sys/types.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include "elf32.h"
+#include "elf64.h"
+#include "libelf.h"
+#include "_libelf.h"
+
+/* WARNING: GENERATED FROM __file__. */
+
+/*
+ * Macros to swap various integral quantities.
+ */
+
+#define SWAP_HALF(X) do { \
+ uint16_t _x = (uint16_t) (X); \
+ uint16_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = _t; \
+ } while (0)
+#define SWAP_WORD(X) 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; \
+ } while (0)
+#define SWAP_ADDR32(X) SWAP_WORD(X)
+#define SWAP_OFF32(X) SWAP_WORD(X)
+#define SWAP_SWORD(X) SWAP_WORD(X)
+#define SWAP_WORD64(X) 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; \
+ } while (0)
+#define SWAP_ADDR64(X) SWAP_WORD64(X)
+#define SWAP_LWORD(X) SWAP_WORD64(X)
+#define SWAP_OFF64(X) SWAP_WORD64(X)
+#define SWAP_SXWORD(X) SWAP_WORD64(X)
+#define SWAP_XWORD(X) SWAP_WORD64(X)
+
+/*
+ * Write out various integral values. 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); \
+ unsigned const 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 = (X); \
+ unsigned char *const _p = (unsigned char *) (P); \
+ unsigned const 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 = (X); \
+ unsigned char *const _p = (unsigned char *) (P); \
+ unsigned const 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)
+
+/*
+ * Read in various integral values. The source pointer could be
+ * unaligned. Values are read in 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) 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; \
+ } while (0)
+#define READ_ADDR32(P,X) READ_WORD(P,X)
+#define READ_OFF32(P,X) READ_WORD(P,X)
+#define READ_SWORD(P,X) READ_WORD(P,X)
+#define READ_WORD64(P,X) 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; \
+ } while (0)
+#define READ_ADDR64(P,X) READ_WORD64(P,X)
+#define READ_LWORD(P,X) READ_WORD64(P,X)
+#define READ_OFF64(P,X) READ_WORD64(P,X)
+#define READ_SXWORD(P,X) READ_WORD64(P,X)
+#define READ_XWORD(P,X) READ_WORD64(P,X)
+#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))
+
+divert(-1)
+
+/*
+ * Generate conversion routines for converting between in-memory and
+ * file representations of Elf data structures.
+ *
+ * `In-memory' representations of an Elf data structure use natural
+ * alignments and native byte ordering. This allows arithmetic and
+ * casting to work as expected. On the other hand the `file'
+ * representation of an ELF data structure could be packed tighter
+ * than its `in-memory' representation, and could be of a differing
+ * byte order. An additional complication is that `ar' only pads data
+ * to even addresses and so ELF archive member data being read from
+ * inside an `ar' archive could end up at misaligned memory addresses.
+ *
+ * Consequently, 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.
+ */
+
+include(SRCDIR`/elf_types.m4')
+
+/*
+ * `IGNORE'_* flags turn off generation of template code.
+ */
+
+define(`IGNORE',
+ `define(IGNORE_$1`'32, 1)
+ define(IGNORE_$1`'64, 1)')
+
+IGNORE(MOVEP)
+IGNORE(NOTE)
+
+define(IGNORE_BYTE, 1) /* 'lator, leave 'em bytes alone */
+define(IGNORE_NOTE, 1)
+define(IGNORE_SXWORD32, 1)
+define(IGNORE_XWORD32, 1)
+
+/*
+ * `BASE'_XXX flags cause class agnostic template functions
+ * to be generated.
+ */
+
+define(`BASE_BYTE', 1)
+define(`BASE_HALF', 1)
+define(`BASE_NOTE', 1)
+define(`BASE_WORD', 1)
+define(`BASE_LWORD', 1)
+define(`BASE_SWORD', 1)
+define(`BASE_XWORD', 1)
+define(`BASE_SXWORD', 1)
+
+/*
+ * `SIZEDEP'_XXX flags cause 32/64 bit variants to be generated
+ * for each primitive type.
+ */
+
+define(`SIZEDEP_ADDR', 1)
+define(`SIZEDEP_OFF', 1)
+
+/*
+ * `Primitive' ELF types are those that are an alias for an integral
+ * type. They have no internal structure. These can be copied using
+ * a `memcpy()', and byteswapped in straightforward way.
+ *
+ * Macro use:
+ * `$1': Name of the ELF type.
+ * `$2': C structure name suffix
+ * `$3': ELF class specifier for symbols, one of [`', `32', `64']
+ * `$4': ELF class specifier for types, one of [`32', `64']
+ */
+define(`MAKEPRIM_TO_F',`
+static void
+libelf_cvt_$1$3_tof(char *dst, char *src, size_t count, int byteswap)
+{
+ Elf$4_$2 t, *s = (Elf$4_$2 *) (uintptr_t) src;
+ size_t c;
+
+ if (dst == src && !byteswap)
+ return;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*s));
+ return;
+ }
+
+ for (c = 0; c < count; c++) {
+ t = *s++;
+ SWAP_$1$3(t);
+ WRITE_$1$3(dst,t);
+ }
+}
+')
+
+define(`MAKEPRIM_TO_M',`
+static void
+libelf_cvt_$1$3_tom(char *dst, char *src, size_t count, int byteswap)
+{
+ Elf$4_$2 t, *d = (Elf$4_$2 *) (uintptr_t) dst;
+ size_t c;
+
+ if (dst == src && !byteswap)
+ return;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*d));
+ return;
+ }
+
+ for (c = 0; c < count; c++) {
+ READ_$1$3(src,t);
+ SWAP_$1$3(t);
+ *d++ = t;
+ }
+}
+')
+
+define(`SWAP_FIELD',
+ `ifdef(`IGNORE_'$2,`',
+ `ifelse(BASE_$2,1,
+ `SWAP_$2(t.$1);
+ ',
+ `ifelse($2,BYTE,`',
+ `ifelse($2,IDENT,`',
+ `SWAP_$2'SZ()`(t.$1);
+ ')')')')')
+define(`SWAP_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
+
+define(`SWAP_STRUCT',
+ `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
+ SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+define(`WRITE_FIELD',
+ `ifelse(BASE_$2,1,
+ `WRITE_$2(dst,t.$1);
+ ',
+ `ifelse($2,IDENT,
+ `WRITE_$2(dst,t.$1);
+ ',
+ `WRITE_$2'SZ()`(dst,t.$1);
+ ')')')
+define(`WRITE_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
+
+define(`WRITE_STRUCT',
+ `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
+ WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+define(`READ_FIELD',
+ `ifelse(BASE_$2,1,
+ `READ_$2(s,t.$1);
+ ',
+ `ifelse($2,IDENT,
+ `READ_$2(s,t.$1);
+ ',
+ `READ_$2'SZ()`(s,t.$1);
+ ')')')
+
+define(`READ_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `READ_FIELD($1)READ_MEMBERS(shift($@))')')
+
+define(`READ_STRUCT',
+ `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
+ READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+/*
+ * Converters for non-integral ELF data 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(`MAKE_TO_F',
+ `ifdef(`IGNORE_'$1$3,`',`
+static void
+libelf_cvt$3_$1_tof(char *dst, char *src, size_t count, int byteswap)
+{
+ Elf$3_$2 t, *s;
+ size_t c;
+
+ 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)
+ }
+}
+')')
+
+define(`MAKE_TO_M',
+ `ifdef(`IGNORE_'$1$3,`',`
+static void
+libelf_cvt$3_$1_tom(char *dst, 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 = (unsigned char *) src + (count - 1) * fsz;
+
+ while (count--) {
+ s = s0;
+ READ_STRUCT($2,$3)
+ if (byteswap) {
+ SWAP_STRUCT($2,$3)
+ }
+ *d-- = t; s0 -= fsz;
+ }
+}
+')')
+
+/*
+ * Make type convertor functions from the type definition
+ * of the ELF type:
+ * - if the type is a base (i.e., `primitive') type:
+ * - if it is marked as to be ignored (i.e., `IGNORE_'TYPE)
+ * is defined, we skip the code generation step.
+ * - if the type is declared as `SIZEDEP', then 32 and 64 bit
+ * variants of the conversion functions are generated.
+ * - otherwise a 32 bit variant is generated.
+ * - if the type is a structure type, we generate 32 and 64 bit
+ * variants of the conversion functions.
+ */
+
+define(`MAKE_TYPE_CONVERTER',
+ `ifdef(`BASE'_$1,
+ `ifdef(`IGNORE_'$1,`',
+ `MAKEPRIM_TO_F($1,$2,`',64)
+ MAKEPRIM_TO_M($1,$2,`',64)')',
+ `ifdef(`SIZEDEP_'$1,
+ `MAKEPRIM_TO_F($1,$2,32,32)dnl
+ MAKEPRIM_TO_M($1,$2,32,32)dnl
+ MAKEPRIM_TO_F($1,$2,64,64)dnl
+ MAKEPRIM_TO_M($1,$2,64,64)',
+ `MAKE_TO_F($1,$2,32)dnl
+ MAKE_TO_F($1,$2,64)dnl
+ MAKE_TO_M($1,$2,32)dnl
+ MAKE_TO_M($1,$2,64)')')
+')
+
+define(`MAKE_TYPE_CONVERTERS',
+ `ifelse($#,1,`',
+ `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
+
+divert(0)
+
+/*
+ * Sections of type ELF_T_BYTE are never byteswapped, consequently a
+ * simple memcpy suffices for both directions of conversion.
+ */
+
+static void
+libelf_cvt_BYTE_tox(char *dst, char *src, size_t count, int byteswap)
+{
+ (void) byteswap;
+ if (dst != src)
+ (void) memcpy(dst, src, count);
+}
+
+/*
+ * 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.
+ */
+static void
+libelf_cvt_NOTE_tom(char *dst, char *src, size_t count, int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz;
+
+ if (dst == src && !byteswap)
+ return;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return;
+ }
+
+ while (count > sizeof(Elf_Note)) {
+
+ READ_WORD(src, namesz);
+ READ_WORD(src, descsz);
+ READ_WORD(src, type);
+
+ if (byteswap) {
+ SWAP_WORD(namesz);
+ SWAP_WORD(descsz);
+ SWAP_WORD(type);
+ }
+
+ en = (Elf_Note *) (uintptr_t) dst;
+ en->n_namesz = namesz;
+ en->n_descsz = descsz;
+ en->n_type = type;
+
+ dst += sizeof(Elf_Note);
+
+ ROUNDUP2(namesz, 4);
+ ROUNDUP2(descsz, 4);
+
+ sz = namesz + descsz;
+
+ if (count < sz)
+ sz = count;
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+ count -= sz;
+ }
+}
+
+static void
+libelf_cvt_NOTE_tof(char *dst, char *src, size_t count, int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz;
+
+ if (dst == src && !byteswap)
+ return;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return;
+ }
+
+ while (count > sizeof(Elf_Note)) {
+
+ en = (Elf_Note *) (uintptr_t) src;
+ namesz = en->n_namesz;
+ descsz = en->n_descsz;
+ type = en->n_type;
+
+ if (byteswap) {
+ 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);
+
+ ROUNDUP2(namesz, 4);
+ ROUNDUP2(descsz, 4);
+
+ sz = namesz + descsz;
+
+ if (count < sz)
+ sz = count;
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+ count -= sz;
+ }
+}
+
+MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
+
+struct converters {
+ void (*tof32)(char *dst, char *src, size_t cnt, int byteswap);
+ void (*tom32)(char *dst, char *src, size_t cnt, int byteswap);
+ void (*tof64)(char *dst, char *src, size_t cnt, int byteswap);
+ void (*tom64)(char *dst, char *src, size_t cnt, int byteswap);
+};
+
+divert(-1)
+define(`CONV',
+ `ifdef(`IGNORE_'$1$2,
+ `.$3$2 = NULL',
+ `ifdef(`BASE_'$1,
+ `ifdef(`IGNORE_'$1,
+ `.$3$2 = NULL',
+ `.$3$2 = libelf_cvt_$1_$3')',
+ `ifdef(`SIZEDEP_'$1,
+ `.$3$2 = libelf_cvt_$1$2_$3',
+ `.$3$2 = libelf_cvt$2_$1_$3')')')')
+
+define(`CONVERTER_NAME',
+ `[ELF_T_$1] = {
+ CONV($1,32,tof), CONV($1,32,tom),
+ CONV($1,64,tof), CONV($1,64,tom) },')')
+
+define(`CONVERTER_NAMES',
+ `ifelse($#,1,`',
+ `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
+
+undefine(`IGNORE_BYTE32')
+undefine(`IGNORE_BYTE64')
+divert(0)
+
+static struct converters cvt[ELF_T_NUM] = {
+CONVERTER_NAMES(ELF_TYPE_LIST)
+
+ /*
+ * Types that needs 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
+ }
+};
+
+void (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
+ (char *_dst, char *_src, size_t _cnt, int _byteswap)
+{
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+ assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
+
+ if (t >= ELF_T_NUM ||
+ (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) ||
+ (direction != ELF_TOFILE && direction != ELF_TOMEMORY))
+ return (NULL);
+
+ return ((elfclass == ELFCLASS32) ?
+ (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
+ (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
+}