diff options
Diffstat (limited to 'ext/libelf/libelf_convert.m4')
-rw-r--r-- | ext/libelf/libelf_convert.m4 | 657 |
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)); +} |