freebsd-nq/contrib/elftoolchain/libelf/libelf_convert.m4
Ed Maste ae500c1ff8 Update to ELF Tool Chain r3668
Highlights:
- Make sure that only TLS sections are sorted into TLS segment.
- Fixed multiple errors in "Section to Segment mapping".
- Man page updates
- ar improvements
- elfcopy: avoid filter_reloc uninitialized variable for rela
- elfcopy: avoid stripping relocations from static binaries
- readelf: avoid printing directory in front of absolute path
- readelf: add NT_FREEBSD_FEATURE_CTL FreeBSD note type
- test improvements

NOTES:

Some of these changes originated in FreeBSD and simply reduce diffs
between contrib and vendor.

ELF Tool Chain ar is not (currently) used in FreeBSD, and there are
improvements in both FreeBSD and ELF Tool Chain ar that are not in
the other.

Sponsored by:	The FreeBSD Foundation
2019-01-10 14:35:23 +00:00

1098 lines
28 KiB
Plaintext

/*-
* 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 "_libelf.h"
ELFTC_VCSID("$Id: libelf_convert.m4 3632 2018-10-10 21:12:43Z jkoshy $");
/* 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->n_namesz = namesz;
en->n_descsz = descsz;
en->n_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->n_namesz;
descsz = en->n_descsz;
type = en->n_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);
#if 0
assert(elfmachine >= EM_NONE && elfmachine < EM__LAST__);
#endif
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));
}