1/*-
2 * Copyright (c) 2006 Joseph Koshy
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28
29#include <assert.h>
30#include <string.h>
31
32#include "elf32.h"
33#include "elf64.h"
34#include "libelf.h"
35#include "_libelf.h"
36
37/* WARNING: GENERATED FROM __file__. */
38
39/*
40 * Macros to swap various integral quantities.
41 */
42
43#define	SWAP_HALF(X) 	do {						\
44		uint16_t _x = (uint16_t) (X);				\
45		uint16_t _t = _x & 0xFF;				\
46		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
47		(X) = _t;						\
48	} while (0)
49#define	SWAP_WORD(X) 	do {						\
50		uint32_t _x = (uint32_t) (X);				\
51		uint32_t _t = _x & 0xFF;				\
52		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
53		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
54		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
55		(X) = _t;						\
56	} while (0)
57#define	SWAP_ADDR32(X)	SWAP_WORD(X)
58#define	SWAP_OFF32(X)	SWAP_WORD(X)
59#define	SWAP_SWORD(X)	SWAP_WORD(X)
60#define	SWAP_WORD64(X)	do {						\
61		uint64_t _x = (uint64_t) (X);				\
62		uint64_t _t = _x & 0xFF;				\
63		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
64		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
65		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
66		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
67		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
68		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
69		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
70		(X) = _t;						\
71	} while (0)
72#define	SWAP_ADDR64(X)	SWAP_WORD64(X)
73#define	SWAP_LWORD(X)	SWAP_WORD64(X)
74#define	SWAP_OFF64(X)	SWAP_WORD64(X)
75#define	SWAP_SXWORD(X)	SWAP_WORD64(X)
76#define	SWAP_XWORD(X)	SWAP_WORD64(X)
77
78/*
79 * Write out various integral values.  The destination pointer could
80 * be unaligned.  Values are written out in native byte order.  The
81 * destination pointer is incremented after the write.
82 */
83#define	WRITE_BYTE(P,X) do {						\
84		unsigned char *const _p = (unsigned char *) (P);	\
85		_p[0]		= (unsigned char) (X);			\
86		(P)		= _p + 1;				\
87	} while (0)
88#define	WRITE_HALF(P,X)	do {						\
89		uint16_t _t	= (X);					\
90		unsigned char *const _p	= (unsigned char *) (P);	\
91		unsigned const char *const _q = (unsigned char *) &_t;	\
92		_p[0]		= _q[0];				\
93		_p[1]		= _q[1];				\
94		(P) 		= _p + 2;				\
95	} while (0)
96#define	WRITE_WORD(P,X)	do {						\
97		uint32_t _t	= (X);					\
98		unsigned char *const _p	= (unsigned char *) (P);	\
99		unsigned const char *const _q = (unsigned char *) &_t;	\
100		_p[0]		= _q[0];				\
101		_p[1]		= _q[1];				\
102		_p[2]		= _q[2];				\
103		_p[3]		= _q[3];				\
104		(P)		= _p + 4;				\
105	} while (0)
106#define	WRITE_ADDR32(P,X)	WRITE_WORD(P,X)
107#define	WRITE_OFF32(P,X)	WRITE_WORD(P,X)
108#define	WRITE_SWORD(P,X)	WRITE_WORD(P,X)
109#define	WRITE_WORD64(P,X)	do {					\
110		uint64_t _t	= (X);					\
111		unsigned char *const _p	= (unsigned char *) (P);	\
112		unsigned const char *const _q = (unsigned char *) &_t;	\
113		_p[0]		= _q[0];				\
114		_p[1]		= _q[1];				\
115		_p[2]		= _q[2];				\
116		_p[3]		= _q[3];				\
117		_p[4]		= _q[4];				\
118		_p[5]		= _q[5];				\
119		_p[6]		= _q[6];				\
120		_p[7]		= _q[7];				\
121		(P)		= _p + 8;				\
122	} while (0)
123#define	WRITE_ADDR64(P,X)	WRITE_WORD64(P,X)
124#define	WRITE_LWORD(P,X)	WRITE_WORD64(P,X)
125#define	WRITE_OFF64(P,X)	WRITE_WORD64(P,X)
126#define	WRITE_SXWORD(P,X)	WRITE_WORD64(P,X)
127#define	WRITE_XWORD(P,X)	WRITE_WORD64(P,X)
128#define	WRITE_IDENT(P,X)	do {					\
129		(void) memcpy((P), (X), sizeof((X)));			\
130		(P)		= (P) + EI_NIDENT;			\
131	} while (0)
132
133/*
134 * Read in various integral values.  The source pointer could be
135 * unaligned.  Values are read in in native byte order.  The source
136 * pointer is incremented appropriately.
137 */
138
139#define	READ_BYTE(P,X)	do {						\
140		const unsigned char *const _p =				\
141			(const unsigned char *) (P);			\
142		(X)		= _p[0];				\
143		(P)		= (P) + 1;				\
144	} while (0)
145#define	READ_HALF(P,X)	do {						\
146		uint16_t _t;						\
147		unsigned char *const _q = (unsigned char *) &_t;	\
148		const unsigned char *const _p =				\
149			(const unsigned char *) (P);			\
150		_q[0]		= _p[0];				\
151		_q[1]		= _p[1];				\
152		(P)		= (P) + 2;				\
153		(X)		= _t;					\
154	} while (0)
155#define	READ_WORD(P,X)	do {						\
156		uint32_t _t;						\
157		unsigned char *const _q = (unsigned char *) &_t;	\
158		const unsigned char *const _p =				\
159			(const unsigned char *) (P);			\
160		_q[0]		= _p[0];				\
161		_q[1]		= _p[1];				\
162		_q[2]		= _p[2];				\
163		_q[3]		= _p[3];				\
164		(P)		= (P) + 4;				\
165		(X)		= _t;					\
166	} while (0)
167#define	READ_ADDR32(P,X)	READ_WORD(P,X)
168#define	READ_OFF32(P,X)		READ_WORD(P,X)
169#define	READ_SWORD(P,X)		READ_WORD(P,X)
170#define	READ_WORD64(P,X)	do {					\
171		uint64_t _t;						\
172		unsigned char *const _q = (unsigned char *) &_t;	\
173		const unsigned char *const _p =				\
174			(const unsigned char *) (P);			\
175		_q[0]		= _p[0];				\
176		_q[1]		= _p[1];				\
177		_q[2]		= _p[2];				\
178		_q[3]		= _p[3];				\
179		_q[4]		= _p[4];				\
180		_q[5]		= _p[5];				\
181		_q[6]		= _p[6];				\
182		_q[7]		= _p[7];				\
183		(P)		= (P) + 8;				\
184		(X)		= _t;					\
185	} while (0)
186#define	READ_ADDR64(P,X)	READ_WORD64(P,X)
187#define	READ_LWORD(P,X)		READ_WORD64(P,X)
188#define	READ_OFF64(P,X)		READ_WORD64(P,X)
189#define	READ_SXWORD(P,X)	READ_WORD64(P,X)
190#define	READ_XWORD(P,X)		READ_WORD64(P,X)
191#define	READ_IDENT(P,X)		do {					\
192		(void) memcpy((X), (P), sizeof((X)));			\
193		(P)		= (P) + EI_NIDENT;			\
194	} while (0)
195
196#define	ROUNDUP2(V,N)	(V) = ((((V) + (N) - 1)) & ~((N) - 1))
197
198divert(-1)
199
200/*
201 * Generate conversion routines for converting between in-memory and
202 * file representations of Elf data structures.
203 *
204 * `In-memory' representations of an Elf data structure use natural
205 * alignments and native byte ordering.  This allows arithmetic and
206 * casting to work as expected.  On the other hand the `file'
207 * representation of an ELF data structure could be packed tighter
208 * than its `in-memory' representation, and could be of a differing
209 * byte order.  An additional complication is that `ar' only pads data
210 * to even addresses and so ELF archive member data being read from
211 * inside an `ar' archive could end up at misaligned memory addresses.
212 *
213 * Consequently, casting the `char *' pointers that point to memory
214 * representations (i.e., source pointers for the *_tof() functions
215 * and the destination pointers for the *_tom() functions), is safe,
216 * as these pointers should be correctly aligned for the memory type
217 * already.  However, pointers to file representations have to be
218 * treated as being potentially unaligned and no casting can be done.
219 */
220
221include(SRCDIR`/elf_types.m4')
222
223/*
224 * `IGNORE'_* flags turn off generation of template code.
225 */
226
227define(`IGNORE',
228  `define(IGNORE_$1`'32,	1)
229   define(IGNORE_$1`'64,	1)')
230
231IGNORE(MOVEP)
232IGNORE(NOTE)
233
234define(IGNORE_BYTE,		1)	/* 'lator, leave 'em bytes alone */
235define(IGNORE_NOTE,		1)
236define(IGNORE_SXWORD32,		1)
237define(IGNORE_XWORD32,		1)
238
239/*
240 * `BASE'_XXX flags cause class agnostic template functions
241 * to be generated.
242 */
243
244define(`BASE_BYTE',	1)
245define(`BASE_HALF',	1)
246define(`BASE_NOTE',	1)
247define(`BASE_WORD',	1)
248define(`BASE_LWORD',	1)
249define(`BASE_SWORD',	1)
250define(`BASE_XWORD',	1)
251define(`BASE_SXWORD',	1)
252
253/*
254 * `SIZEDEP'_XXX flags cause 32/64 bit variants to be generated
255 * for each primitive type.
256 */
257
258define(`SIZEDEP_ADDR',	1)
259define(`SIZEDEP_OFF',	1)
260
261/*
262 * `Primitive' ELF types are those that are an alias for an integral
263 * type.  They have no internal structure. These can be copied using
264 * a `memcpy()', and byteswapped in straightforward way.
265 *
266 * Macro use:
267 * `$1': Name of the ELF type.
268 * `$2': C structure name suffix
269 * `$3': ELF class specifier for symbols, one of [`', `32', `64']
270 * `$4': ELF class specifier for types, one of [`32', `64']
271 */
272define(`MAKEPRIM_TO_F',`
273static void
274libelf_cvt_$1$3_tof(char *dst, char *src, size_t count, int byteswap)
275{
276	Elf$4_$2 t, *s = (Elf$4_$2 *) (uintptr_t) src;
277	size_t c;
278
279	if (dst == src && !byteswap)
280		return;
281
282	if (!byteswap) {
283		(void) memcpy(dst, src, count * sizeof(*s));
284		return;
285	}
286
287	for (c = 0; c < count; c++) {
288		t = *s++;
289		SWAP_$1$3(t);
290		WRITE_$1$3(dst,t);
291	}
292}
293')
294
295define(`MAKEPRIM_TO_M',`
296static void
297libelf_cvt_$1$3_tom(char *dst, char *src, size_t count, int byteswap)
298{
299	Elf$4_$2 t, *d = (Elf$4_$2 *) (uintptr_t) dst;
300	size_t c;
301
302	if (dst == src && !byteswap)
303		return;
304
305	if (!byteswap) {
306		(void) memcpy(dst, src, count * sizeof(*d));
307		return;
308	}
309
310	for (c = 0; c < count; c++) {
311		READ_$1$3(src,t);
312		SWAP_$1$3(t);
313		*d++ = t;
314	}
315}
316')
317
318define(`SWAP_FIELD',
319  `ifdef(`IGNORE_'$2,`',
320    `ifelse(BASE_$2,1,
321      `SWAP_$2(t.$1);
322			',
323      `ifelse($2,BYTE,`',
324        `ifelse($2,IDENT,`',
325          `SWAP_$2'SZ()`(t.$1);
326			')')')')')
327define(`SWAP_MEMBERS',
328  `ifelse($#,1,`/**/',
329     `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
330
331define(`SWAP_STRUCT',
332  `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
333			SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
334
335define(`WRITE_FIELD',
336  `ifelse(BASE_$2,1,
337    `WRITE_$2(dst,t.$1);
338		',
339    `ifelse($2,IDENT,
340      `WRITE_$2(dst,t.$1);
341		',
342      `WRITE_$2'SZ()`(dst,t.$1);
343		')')')
344define(`WRITE_MEMBERS',
345  `ifelse($#,1,`/**/',
346    `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
347
348define(`WRITE_STRUCT',
349  `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
350		WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
351
352define(`READ_FIELD',
353  `ifelse(BASE_$2,1,
354    `READ_$2(s,t.$1);
355		',
356    `ifelse($2,IDENT,
357      `READ_$2(s,t.$1);
358		',
359      `READ_$2'SZ()`(s,t.$1);
360		')')')
361
362define(`READ_MEMBERS',
363  `ifelse($#,1,`/**/',
364    `READ_FIELD($1)READ_MEMBERS(shift($@))')')
365
366define(`READ_STRUCT',
367  `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
368		READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
369
370/*
371 * Converters for non-integral ELF data structures.
372 *
373 * When converting data to file representation, the source pointer
374 * will be naturally aligned for a data structure's in-memory
375 * representation.  When converting data to memory, the destination
376 * pointer will be similarly aligned.
377 *
378 * For in-place conversions, when converting to file representations,
379 * the source buffer is large enough to hold `file' data.  When
380 * converting from file to memory, we need to be careful to work
381 * `backwards', to avoid overwriting unconverted data.
382 *
383 * Macro use:
384 * `$1': Name of the ELF type.
385 * `$2': C structure name suffix.
386 * `$3': ELF class specifier, one of [`', `32', `64']
387 */
388
389define(`MAKE_TO_F',
390  `ifdef(`IGNORE_'$1$3,`',`
391static void
392libelf_cvt$3_$1_tof(char *dst, char *src, size_t count, int byteswap)
393{
394	Elf$3_$2	t, *s;
395	size_t c;
396
397	s = (Elf$3_$2 *) (uintptr_t) src;
398	for (c = 0; c < count; c++) {
399		t = *s++;
400		if (byteswap) {
401			SWAP_STRUCT($2,$3)
402		}
403		WRITE_STRUCT($2,$3)
404	}
405}
406')')
407
408define(`MAKE_TO_M',
409  `ifdef(`IGNORE_'$1$3,`',`
410static void
411libelf_cvt$3_$1_tom(char *dst, char *src, size_t count, int byteswap)
412{
413	Elf$3_$2	 t, *d;
414	unsigned char	*s,*s0;
415	size_t		fsz;
416
417	fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT);
418	d   = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
419	s0  = (unsigned char *) src + (count - 1) * fsz;
420
421	while (count--) {
422		s = s0;
423		READ_STRUCT($2,$3)
424		if (byteswap) {
425			SWAP_STRUCT($2,$3)
426		}
427		*d-- = t; s0 -= fsz;
428	}
429}
430')')
431
432/*
433 * Make type convertor functions from the type definition
434 * of the ELF type:
435 * - if the type is a base (i.e., `primitive') type:
436 *   - if it is marked as to be ignored (i.e., `IGNORE_'TYPE)
437 *     is defined, we skip the code generation step.
438 *   - if the type is declared as `SIZEDEP', then 32 and 64 bit
439 *     variants of the conversion functions are generated.
440 *   - otherwise a 32 bit variant is generated.
441 * - if the type is a structure type, we generate 32 and 64 bit
442 *   variants of the conversion functions.
443 */
444
445define(`MAKE_TYPE_CONVERTER',
446  `ifdef(`BASE'_$1,
447    `ifdef(`IGNORE_'$1,`',
448      `MAKEPRIM_TO_F($1,$2,`',64)
449       MAKEPRIM_TO_M($1,$2,`',64)')',
450    `ifdef(`SIZEDEP_'$1,
451      `MAKEPRIM_TO_F($1,$2,32,32)dnl
452       MAKEPRIM_TO_M($1,$2,32,32)dnl
453       MAKEPRIM_TO_F($1,$2,64,64)dnl
454       MAKEPRIM_TO_M($1,$2,64,64)',
455      `MAKE_TO_F($1,$2,32)dnl
456       MAKE_TO_F($1,$2,64)dnl
457       MAKE_TO_M($1,$2,32)dnl
458       MAKE_TO_M($1,$2,64)')')
459')
460
461define(`MAKE_TYPE_CONVERTERS',
462  `ifelse($#,1,`',
463    `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
464
465divert(0)
466
467/*
468 * Sections of type ELF_T_BYTE are never byteswapped, consequently a
469 * simple memcpy suffices for both directions of conversion.
470 */
471
472static void
473libelf_cvt_BYTE_tox(char *dst, char *src, size_t count, int byteswap)
474{
475	(void) byteswap;
476	if (dst != src)
477		(void) memcpy(dst, src, count);
478}
479
480/*
481 * Elf_Note structures comprise a fixed size header followed by variable
482 * length strings.  The fixed size header needs to be byte swapped, but
483 * not the strings.
484 *
485 * Argument `count' denotes the total number of bytes to be converted.
486 */
487static void
488libelf_cvt_NOTE_tom(char *dst, char *src, size_t count, int byteswap)
489{
490	uint32_t namesz, descsz, type;
491	Elf_Note *en;
492	size_t sz;
493
494	if (dst == src && !byteswap)
495		return;
496
497	if (!byteswap) {
498		(void) memcpy(dst, src, count);
499		return;
500	}
501
502	while (count > sizeof(Elf_Note)) {
503
504		READ_WORD(src, namesz);
505		READ_WORD(src, descsz);
506		READ_WORD(src, type);
507
508		if (byteswap) {
509			SWAP_WORD(namesz);
510			SWAP_WORD(descsz);
511			SWAP_WORD(type);
512		}
513
514		en = (Elf_Note *) (uintptr_t) dst;
515		en->n_namesz = namesz;
516		en->n_descsz = descsz;
517		en->n_type = type;
518
519		dst += sizeof(Elf_Note);
520
521		ROUNDUP2(namesz, 4);
522		ROUNDUP2(descsz, 4);
523
524		sz = namesz + descsz;
525
526		if (count < sz)
527			sz = count;
528
529		(void) memcpy(dst, src, sz);
530
531		src += sz;
532		dst += sz;
533		count -= sz;
534	}
535}
536
537static void
538libelf_cvt_NOTE_tof(char *dst, char *src, size_t count, int byteswap)
539{
540	uint32_t namesz, descsz, type;
541	Elf_Note *en;
542	size_t sz;
543
544	if (dst == src && !byteswap)
545		return;
546
547	if (!byteswap) {
548		(void) memcpy(dst, src, count);
549		return;
550	}
551
552	while (count > sizeof(Elf_Note)) {
553
554		en = (Elf_Note *) (uintptr_t) src;
555		namesz = en->n_namesz;
556		descsz = en->n_descsz;
557		type = en->n_type;
558
559		if (byteswap) {
560			SWAP_WORD(namesz);
561			SWAP_WORD(descsz);
562			SWAP_WORD(type);
563		}
564
565
566		WRITE_WORD(dst, namesz);
567		WRITE_WORD(dst, descsz);
568		WRITE_WORD(dst, type);
569
570		src += sizeof(Elf_Note);
571
572		ROUNDUP2(namesz, 4);
573		ROUNDUP2(descsz, 4);
574
575		sz = namesz + descsz;
576
577		if (count < sz)
578			sz = count;
579
580		(void) memcpy(dst, src, sz);
581
582		src += sz;
583		dst += sz;
584		count -= sz;
585	}
586}
587
588MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
589
590struct converters {
591	void	(*tof32)(char *dst, char *src, size_t cnt, int byteswap);
592	void	(*tom32)(char *dst, char *src, size_t cnt, int byteswap);
593	void	(*tof64)(char *dst, char *src, size_t cnt, int byteswap);
594	void	(*tom64)(char *dst, char *src, size_t cnt, int byteswap);
595};
596
597divert(-1)
598define(`CONV',
599  `ifdef(`IGNORE_'$1$2,
600    `.$3$2 = NULL',
601    `ifdef(`BASE_'$1,
602      `ifdef(`IGNORE_'$1,
603	`.$3$2 = NULL',
604        `.$3$2 = libelf_cvt_$1_$3')',
605      `ifdef(`SIZEDEP_'$1,
606        `.$3$2 = libelf_cvt_$1$2_$3',
607        `.$3$2 = libelf_cvt$2_$1_$3')')')')
608
609define(`CONVERTER_NAME',
610  `[ELF_T_$1] = {
611        CONV($1,32,tof), CONV($1,32,tom),
612        CONV($1,64,tof), CONV($1,64,tom) },')')
613
614define(`CONVERTER_NAMES',
615  `ifelse($#,1,`',
616    `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
617
618undefine(`IGNORE_BYTE32')
619undefine(`IGNORE_BYTE64')
620divert(0)
621
622static struct converters cvt[ELF_T_NUM] = {
623CONVERTER_NAMES(ELF_TYPE_LIST)
624
625	/*
626	 * Types that needs hand-coded converters follow.
627	 */
628
629	[ELF_T_BYTE] = {
630		.tof32 = libelf_cvt_BYTE_tox,
631		.tom32 = libelf_cvt_BYTE_tox,
632		.tof64 = libelf_cvt_BYTE_tox,
633		.tom64 = libelf_cvt_BYTE_tox
634	},
635	[ELF_T_NOTE] = {
636		.tof32 = libelf_cvt_NOTE_tof,
637		.tom32 = libelf_cvt_NOTE_tom,
638		.tof64 = libelf_cvt_NOTE_tof,
639		.tom64 = libelf_cvt_NOTE_tom
640	}
641};
642
643void (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
644 (char *_dst, char *_src, size_t _cnt, int _byteswap)
645{
646	assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
647	assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
648
649	if (t >= ELF_T_NUM ||
650	    (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) ||
651	    (direction != ELF_TOFILE && direction != ELF_TOMEMORY))
652		return (NULL);
653
654	return ((elfclass == ELFCLASS32) ?
655	    (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
656	    (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
657}
658