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