#ifndef _PRIVATE_LIBELF_H_
#define _PRIVATE_LIBELF_H_
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/queue.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#if defined(__DragonFly__)
#define LIBELF_ARCH EM_X86_64
#define LIBELF_BYTEORDER ELFDATA2LSB
#define LIBELF_CLASS ELFCLASS64
#endif
#if defined(__DragonFly__)
#define ELFTC_BYTE_ORDER _BYTE_ORDER
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
#define ELFTC_HAVE_MMAP 1
#define STAILQ_FOREACH_SAFE STAILQ_FOREACH_MUTABLE
#endif
#if 1
#define _libelf_allocate_data __ei_libelf_allocate_data
#define _libelf_allocate_elf __ei_libelf_allocate_elf
#define _libelf_allocate_scn __ei_libelf_allocate_scn
#define _libelf_cvt_ADDR64_tom __ei_libelf_cvt_ADDR64_tom
#define _libelf_cvt_BYTE_tox __ei_libelf_cvt_BYTE_tox
#define _libelf_cvt_CAP64_tom __ei_libelf_cvt_CAP64_tom
#define _libelf_cvt_DYN64_tom __ei_libelf_cvt_DYN64_tom
#define _libelf_cvt_EHDR64_tom __ei_libelf_cvt_EHDR64_tom
#define _libelf_cvt_GNUHASH64_tom __ei_libelf_cvt_GNUHASH64_tom
#define _libelf_cvt_HALF_tom __ei_libelf_cvt_HALF_tom
#define _libelf_cvt_LWORD_tom __ei_libelf_cvt_LWORD_tom
#define _libelf_cvt_MOVE64_tom __ei_libelf_cvt_MOVE64_tom
#define _libelf_cvt_NOTE_tom __ei_libelf_cvt_NOTE_tom
#define _libelf_cvt_OFF64_tom __ei_libelf_cvt_OFF64_tom
#define _libelf_cvt_PHDR64_tom __ei_libelf_cvt_PHDR64_tom
#define _libelf_cvt_REL64_tom __ei_libelf_cvt_REL64_tom
#define _libelf_cvt_RELA64_tom __ei_libelf_cvt_RELA64_tom
#define _libelf_cvt_SHDR64_tom __ei_libelf_cvt_SHDR64_tom
#define _libelf_cvt_SWORD_tom __ei_libelf_cvt_SWORD_tom
#define _libelf_cvt_SXWORD_tom __ei_libelf_cvt_SXWORD_tom
#define _libelf_cvt_SYM64_tom __ei_libelf_cvt_SYM64_tom
#define _libelf_cvt_SYMINFO64_tom __ei_libelf_cvt_SYMINFO64_tom
#define _libelf_cvt_VDEF64_tom __ei_libelf_cvt_VDEF64_tom
#define _libelf_cvt_VNEED64_tom __ei_libelf_cvt_VNEED64_tom
#define _libelf_cvt_WORD_tom __ei_libelf_cvt_WORD_tom
#define _libelf_cvt_XWORD_tom __ei_libelf_cvt_XWORD_tom
#define _libelf_ehdr __ei_libelf_ehdr
#define _libelf_fsize __ei_libelf_fsize
#define _libelf_get_translator __ei_libelf_get_translator
#define _libelf_getshdr __ei_libelf_getshdr
#define _libelf_init_elf __ei_libelf_init_elf
#define _libelf_load_extended __ei_libelf_load_extended
#define _libelf_load_section_headers __ei_libelf_load_section_headers
#define _libelf_memory __ei_libelf_memory
#define _libelf_msize __ei_libelf_msize
#define _libelf_open_object __ei_libelf_open_object
#define _libelf_read_special_file __ei_libelf_read_special_file
#define _libelf_release_data __ei_libelf_release_data
#define _libelf_release_elf __ei_libelf_release_elf
#define _libelf_release_scn __ei_libelf_release_scn
#define _libelf_xlate_shtype __ei_libelf_xlate_shtype
#define _libelf __ei_libelf
#define elf64_fsize __ei_elf64_fsize
#define elf_getscn __ei_elf_getscn
#define elf_begin _ei_elf_begin
#define elf_end _ei_elf_end
#define elf_errmsg _ei_elf_errmsg
#define elf_errno _ei_elf_errno
#define elf_getdata _ei_elf_getdata
#define elf_nextscn _ei_elf_nextscn
#define elf_strptr _ei_elf_strptr
#define elf_version _ei_elf_version
#define gelf_getshdr _ei_gelf_getshdr
#define gelf_getsym _ei_gelf_getsym
#endif
#define _ELF_DEFINE_EI_OFFSETS() \
_ELF_DEFINE_EI(EI_MAG0, 0, "magic number") \
_ELF_DEFINE_EI(EI_MAG1, 1, "magic number") \
_ELF_DEFINE_EI(EI_MAG2, 2, "magic number") \
_ELF_DEFINE_EI(EI_MAG3, 3, "magic number") \
_ELF_DEFINE_EI(EI_CLASS, 4, "file class") \
_ELF_DEFINE_EI(EI_DATA, 5, "data encoding") \
_ELF_DEFINE_EI(EI_VERSION, 6, "file version") \
_ELF_DEFINE_EI(EI_OSABI, 7, "OS ABI kind") \
_ELF_DEFINE_EI(EI_ABIVERSION, 8, "OS ABI version") \
_ELF_DEFINE_EI(EI_PAD, 9, "padding start") \
_ELF_DEFINE_EI(EI_NIDENT, 16, "total size")
#undef _ELF_DEFINE_EI
#define _ELF_DEFINE_EI(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_EI_OFFSETS()
EI__LAST__
};
#define _ELF_DEFINE_ELFCLASS() \
_ELF_DEFINE_EC(ELFCLASSNONE, 0, "Unknown ELF class") \
_ELF_DEFINE_EC(ELFCLASS32, 1, "32 bit objects") \
_ELF_DEFINE_EC(ELFCLASS64, 2, "64 bit objects")
#undef _ELF_DEFINE_EC
#define _ELF_DEFINE_EC(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_ELFCLASS()
EC__LAST__
};
#define _ELF_DEFINE_ELF_DATA_ENDIANNESS() \
_ELF_DEFINE_ED(ELFDATANONE, 0, "Unknown data endianness") \
_ELF_DEFINE_ED(ELFDATA2LSB, 1, "little endian") \
_ELF_DEFINE_ED(ELFDATA2MSB, 2, "big endian")
#undef _ELF_DEFINE_ED
#define _ELF_DEFINE_ED(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_ELF_DATA_ENDIANNESS()
ED__LAST__
};
#define _ELF_DEFINE_ELF_MAGIC() \
_ELF_DEFINE_EMAG(ELFMAG0, 0x7FU) \
_ELF_DEFINE_EMAG(ELFMAG1, 'E') \
_ELF_DEFINE_EMAG(ELFMAG2, 'L') \
_ELF_DEFINE_EMAG(ELFMAG3, 'F')
#undef _ELF_DEFINE_EMAG
#define _ELF_DEFINE_EMAG(N, V) N = V ,
enum {
_ELF_DEFINE_ELF_MAGIC()
ELFMAG__LAST__
};
#define _ELF_DEFINE_ELF_MACHINES() \
_ELF_DEFINE_EM(EM_NONE, 0, "No machine") \
_ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \
_ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture")
#undef _ELF_DEFINE_EM
#define _ELF_DEFINE_EM(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_ELF_MACHINES()
EM__LAST__
};
#define EV_NONE 0
#define EV_CURRENT 1
#define _ELF_DEFINE_SECTION_INDICES() \
_ELF_DEFINE_SHN(SHN_UNDEF, 0, "undefined section") \
_ELF_DEFINE_SHN(SHN_LORESERVE, 0xFF00U, "start of reserved area") \
_ELF_DEFINE_SHN(SHN_LOPROC, 0xFF00U, \
"start of processor-specific range") \
_ELF_DEFINE_SHN(SHN_BEFORE, 0xFF00U, "used for section ordering") \
_ELF_DEFINE_SHN(SHN_AFTER, 0xFF01U, "used for section ordering") \
_ELF_DEFINE_SHN(SHN_AMD64_LCOMMON, 0xFF02U, "large common block label") \
_ELF_DEFINE_SHN(SHN_MIPS_ACOMMON, 0xFF00U, \
"allocated common symbols in a DSO") \
_ELF_DEFINE_SHN(SHN_MIPS_TEXT, 0xFF01U, "Reserved (obsolete)") \
_ELF_DEFINE_SHN(SHN_MIPS_DATA, 0xFF02U, "Reserved (obsolete)") \
_ELF_DEFINE_SHN(SHN_MIPS_SCOMMON, 0xFF03U, \
"gp-addressable common symbols") \
_ELF_DEFINE_SHN(SHN_MIPS_SUNDEFINED, 0xFF04U, \
"gp-addressable undefined symbols") \
_ELF_DEFINE_SHN(SHN_MIPS_LCOMMON, 0xFF05U, "local common symbols") \
_ELF_DEFINE_SHN(SHN_MIPS_LUNDEFINED, 0xFF06U, \
"local undefined symbols") \
_ELF_DEFINE_SHN(SHN_HIPROC, 0xFF1FU, \
"end of processor-specific range") \
_ELF_DEFINE_SHN(SHN_LOOS, 0xFF20U, \
"start of OS-specific range") \
_ELF_DEFINE_SHN(SHN_SUNW_IGNORE, 0xFF3FU, "used by dtrace") \
_ELF_DEFINE_SHN(SHN_HIOS, 0xFF3FU, \
"end of OS-specific range") \
_ELF_DEFINE_SHN(SHN_ABS, 0xFFF1U, "absolute references") \
_ELF_DEFINE_SHN(SHN_COMMON, 0xFFF2U, "references to COMMON areas") \
_ELF_DEFINE_SHN(SHN_XINDEX, 0xFFFFU, "extended index") \
_ELF_DEFINE_SHN(SHN_HIRESERVE, 0xFFFFU, "end of reserved area")
#undef _ELF_DEFINE_SHN
#define _ELF_DEFINE_SHN(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_SECTION_INDICES()
SHN__LAST__
};
#define _ELF_DEFINE_SECTION_TYPES() \
_ELF_DEFINE_SHT(SHT_NULL, 0, "inactive header") \
_ELF_DEFINE_SHT(SHT_PROGBITS, 1, "program defined information") \
_ELF_DEFINE_SHT(SHT_SYMTAB, 2, "symbol table") \
_ELF_DEFINE_SHT(SHT_STRTAB, 3, "string table") \
_ELF_DEFINE_SHT(SHT_RELA, 4, \
"relocation entries with addends") \
_ELF_DEFINE_SHT(SHT_HASH, 5, "symbol hash table") \
_ELF_DEFINE_SHT(SHT_DYNAMIC, 6, \
"information for dynamic linking") \
_ELF_DEFINE_SHT(SHT_NOTE, 7, "additional notes") \
_ELF_DEFINE_SHT(SHT_NOBITS, 8, "section occupying no space") \
_ELF_DEFINE_SHT(SHT_REL, 9, \
"relocation entries without addends") \
_ELF_DEFINE_SHT(SHT_SHLIB, 10, "reserved") \
_ELF_DEFINE_SHT(SHT_DYNSYM, 11, "symbol table") \
_ELF_DEFINE_SHT(SHT_INIT_ARRAY, 14, \
"pointers to initialization functions") \
_ELF_DEFINE_SHT(SHT_FINI_ARRAY, 15, \
"pointers to termination functions") \
_ELF_DEFINE_SHT(SHT_PREINIT_ARRAY, 16, \
"pointers to functions called before initialization") \
_ELF_DEFINE_SHT(SHT_GROUP, 17, "defines a section group") \
_ELF_DEFINE_SHT(SHT_SYMTAB_SHNDX, 18, \
"used for extended section numbering") \
_ELF_DEFINE_SHT(SHT_LOOS, 0x60000000UL, \
"start of OS-specific range") \
_ELF_DEFINE_SHT(SHT_SUNW_dof, 0x6FFFFFF4UL, \
"used by dtrace") \
_ELF_DEFINE_SHT(SHT_SUNW_cap, 0x6FFFFFF5UL, \
"capability requirements") \
_ELF_DEFINE_SHT(SHT_GNU_ATTRIBUTES, 0x6FFFFFF5UL, \
"object attributes") \
_ELF_DEFINE_SHT(SHT_SUNW_SIGNATURE, 0x6FFFFFF6UL, \
"module verification signature") \
_ELF_DEFINE_SHT(SHT_GNU_HASH, 0x6FFFFFF6UL, \
"GNU Hash sections") \
_ELF_DEFINE_SHT(SHT_GNU_LIBLIST, 0x6FFFFFF7UL, \
"List of libraries to be prelinked") \
_ELF_DEFINE_SHT(SHT_SUNW_ANNOTATE, 0x6FFFFFF7UL, \
"special section where unresolved references are allowed") \
_ELF_DEFINE_SHT(SHT_SUNW_DEBUGSTR, 0x6FFFFFF8UL, \
"debugging information") \
_ELF_DEFINE_SHT(SHT_CHECKSUM, 0x6FFFFFF8UL, \
"checksum for dynamic shared objects") \
_ELF_DEFINE_SHT(SHT_SUNW_DEBUG, 0x6FFFFFF9UL, \
"debugging information") \
_ELF_DEFINE_SHT(SHT_SUNW_move, 0x6FFFFFFAUL, \
"information to handle partially initialized symbols") \
_ELF_DEFINE_SHT(SHT_SUNW_COMDAT, 0x6FFFFFFBUL, \
"section supporting merging of multiple copies of data") \
_ELF_DEFINE_SHT(SHT_SUNW_syminfo, 0x6FFFFFFCUL, \
"additional symbol information") \
_ELF_DEFINE_SHT(SHT_SUNW_verdef, 0x6FFFFFFDUL, \
"symbol versioning information") \
_ELF_DEFINE_SHT(SHT_SUNW_verneed, 0x6FFFFFFEUL, \
"symbol versioning requirements") \
_ELF_DEFINE_SHT(SHT_SUNW_versym, 0x6FFFFFFFUL, \
"symbol versioning table") \
_ELF_DEFINE_SHT(SHT_HIOS, 0x6FFFFFFFUL, \
"end of OS-specific range") \
_ELF_DEFINE_SHT(SHT_LOPROC, 0x70000000UL, \
"start of processor-specific range") \
_ELF_DEFINE_SHT(SHT_ARM_EXIDX, 0x70000001UL, \
"exception index table") \
_ELF_DEFINE_SHT(SHT_ARM_PREEMPTMAP, 0x70000002UL, \
"BPABI DLL dynamic linking preemption map") \
_ELF_DEFINE_SHT(SHT_ARM_ATTRIBUTES, 0x70000003UL, \
"object file compatibility attributes") \
_ELF_DEFINE_SHT(SHT_ARM_DEBUGOVERLAY, 0x70000004UL, \
"overlay debug information") \
_ELF_DEFINE_SHT(SHT_ARM_OVERLAYSECTION, 0x70000005UL, \
"overlay debug information") \
_ELF_DEFINE_SHT(SHT_MIPS_LIBLIST, 0x70000000UL, \
"DSO library information used in link") \
_ELF_DEFINE_SHT(SHT_MIPS_MSYM, 0x70000001UL, \
"MIPS symbol table extension") \
_ELF_DEFINE_SHT(SHT_MIPS_CONFLICT, 0x70000002UL, \
"symbol conflicting with DSO-defined symbols ") \
_ELF_DEFINE_SHT(SHT_MIPS_GPTAB, 0x70000003UL, \
"global pointer table") \
_ELF_DEFINE_SHT(SHT_MIPS_UCODE, 0x70000004UL, \
"reserved") \
_ELF_DEFINE_SHT(SHT_MIPS_DEBUG, 0x70000005UL, \
"reserved (obsolete debug information)") \
_ELF_DEFINE_SHT(SHT_MIPS_REGINFO, 0x70000006UL, \
"register usage information") \
_ELF_DEFINE_SHT(SHT_MIPS_PACKAGE, 0x70000007UL, \
"OSF reserved") \
_ELF_DEFINE_SHT(SHT_MIPS_PACKSYM, 0x70000008UL, \
"OSF reserved") \
_ELF_DEFINE_SHT(SHT_MIPS_RELD, 0x70000009UL, \
"dynamic relocation") \
_ELF_DEFINE_SHT(SHT_MIPS_IFACE, 0x7000000BUL, \
"subprogram interface information") \
_ELF_DEFINE_SHT(SHT_MIPS_CONTENT, 0x7000000CUL, \
"section content classification") \
_ELF_DEFINE_SHT(SHT_MIPS_OPTIONS, 0x7000000DUL, \
"general options") \
_ELF_DEFINE_SHT(SHT_MIPS_DELTASYM, 0x7000001BUL, \
"Delta C++: symbol table") \
_ELF_DEFINE_SHT(SHT_MIPS_DELTAINST, 0x7000001CUL, \
"Delta C++: instance table") \
_ELF_DEFINE_SHT(SHT_MIPS_DELTACLASS, 0x7000001DUL, \
"Delta C++: class table") \
_ELF_DEFINE_SHT(SHT_MIPS_DWARF, 0x7000001EUL, \
"DWARF debug information") \
_ELF_DEFINE_SHT(SHT_MIPS_DELTADECL, 0x7000001FUL, \
"Delta C++: declarations") \
_ELF_DEFINE_SHT(SHT_MIPS_SYMBOL_LIB, 0x70000020UL, \
"symbol-to-library mapping") \
_ELF_DEFINE_SHT(SHT_MIPS_EVENTS, 0x70000021UL, \
"event locations") \
_ELF_DEFINE_SHT(SHT_MIPS_TRANSLATE, 0x70000022UL, \
"???") \
_ELF_DEFINE_SHT(SHT_MIPS_PIXIE, 0x70000023UL, \
"special pixie sections") \
_ELF_DEFINE_SHT(SHT_MIPS_XLATE, 0x70000024UL, \
"address translation table") \
_ELF_DEFINE_SHT(SHT_MIPS_XLATE_DEBUG, 0x70000025UL, \
"SGI internal address translation table") \
_ELF_DEFINE_SHT(SHT_MIPS_WHIRL, 0x70000026UL, \
"intermediate code") \
_ELF_DEFINE_SHT(SHT_MIPS_EH_REGION, 0x70000027UL, \
"C++ exception handling region info") \
_ELF_DEFINE_SHT(SHT_MIPS_XLATE_OLD, 0x70000028UL, \
"obsolete") \
_ELF_DEFINE_SHT(SHT_MIPS_PDR_EXCEPTION, 0x70000029UL, \
"runtime procedure descriptor table exception information") \
_ELF_DEFINE_SHT(SHT_MIPS_ABIFLAGS, 0x7000002AUL, \
"ABI flags") \
_ELF_DEFINE_SHT(SHT_SPARC_GOTDATA, 0x70000000UL, \
"SPARC-specific data") \
_ELF_DEFINE_SHT(SHT_AMD64_UNWIND, 0x70000001UL, \
"unwind tables for the AMD64") \
_ELF_DEFINE_SHT(SHT_ORDERED, 0x7FFFFFFFUL, \
"sort entries in the section") \
_ELF_DEFINE_SHT(SHT_HIPROC, 0x7FFFFFFFUL, \
"end of processor-specific range") \
_ELF_DEFINE_SHT(SHT_LOUSER, 0x80000000UL, \
"start of application-specific range") \
_ELF_DEFINE_SHT(SHT_HIUSER, 0xFFFFFFFFUL, \
"end of application-specific range")
#undef _ELF_DEFINE_SHT
#define _ELF_DEFINE_SHT(N, V, DESCR) N = V ,
enum {
_ELF_DEFINE_SECTION_TYPES()
SHT__LAST__ = SHT_HIUSER
};
#define PN_XNUM 0xFFFFU
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Lword;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
typedef struct {
Elf64_Xword c_tag;
union {
Elf64_Xword c_val;
Elf64_Addr c_ptr;
} c_un;
} Elf64_Cap;
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
typedef struct {
uint32_t n_namesz;
uint32_t n_descsz;
uint32_t n_type;
} Elf_Note;
typedef struct {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
} Elf64_Phdr;
typedef struct {
Elf64_Lword m_value;
Elf64_Xword m_info;
Elf64_Xword m_poffset;
Elf64_Half m_repeat;
Elf64_Half m_stride;
} Elf64_Move;
typedef struct {
Elf64_Word sh_name;
Elf64_Word sh_type;
Elf64_Xword sh_flags;
Elf64_Addr sh_addr;
Elf64_Off sh_offset;
Elf64_Xword sh_size;
Elf64_Word sh_link;
Elf64_Word sh_info;
Elf64_Xword sh_addralign;
Elf64_Xword sh_entsize;
} Elf64_Shdr;
typedef struct {
Elf64_Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf64_Half st_shndx;
Elf64_Addr st_value;
Elf64_Xword st_size;
} Elf64_Sym;
typedef struct {
Elf64_Half si_boundto;
Elf64_Half si_flags;
} Elf64_Syminfo;
typedef struct {
Elf64_Addr r_offset;
Elf64_Xword r_info;
} Elf64_Rel;
typedef struct {
Elf64_Addr r_offset;
Elf64_Xword r_info;
Elf64_Sxword r_addend;
} Elf64_Rela;
typedef struct {
Elf64_Word vda_name;
Elf64_Word vda_next;
} Elf64_Verdaux;
typedef struct {
Elf64_Word vna_hash;
Elf64_Half vna_flags;
Elf64_Half vna_other;
Elf64_Word vna_name;
Elf64_Word vna_next;
} Elf64_Vernaux;
typedef struct {
Elf64_Half vd_version;
Elf64_Half vd_flags;
Elf64_Half vd_ndx;
Elf64_Half vd_cnt;
Elf64_Word vd_hash;
Elf64_Word vd_aux;
Elf64_Word vd_next;
} Elf64_Verdef;
typedef struct {
Elf64_Half vn_version;
Elf64_Half vn_cnt;
Elf64_Word vn_file;
Elf64_Word vn_aux;
Elf64_Word vn_next;
} Elf64_Verneed;
typedef struct {
uint32_t gh_nbuckets;
uint32_t gh_symndx;
uint32_t gh_maskwords;
uint32_t gh_shift2;
} Elf_GNU_Hash_Header;
typedef struct _Elf Elf;
typedef struct _Elf_Scn Elf_Scn;
typedef enum {
ELF_K_NONE = 0,
ELF_K_AR,
ELF_K_COFF,
ELF_K_ELF,
ELF_K_NUM
} Elf_Kind;
typedef enum {
ELF_T_ADDR,
ELF_T_BYTE,
ELF_T_CAP,
ELF_T_DYN,
ELF_T_EHDR,
ELF_T_HALF,
ELF_T_LWORD,
ELF_T_MOVE,
ELF_T_MOVEP,
ELF_T_NOTE,
ELF_T_OFF,
ELF_T_PHDR,
ELF_T_REL,
ELF_T_RELA,
ELF_T_SHDR,
ELF_T_SWORD,
ELF_T_SXWORD,
ELF_T_SYMINFO,
ELF_T_SYM,
ELF_T_VDEF,
ELF_T_VNEED,
ELF_T_WORD,
ELF_T_XWORD,
ELF_T_GNUHASH,
ELF_T_NUM
} Elf_Type;
#define ELF_T_FIRST ELF_T_ADDR
#define ELF_T_LAST ELF_T_GNUHASH
typedef enum {
ELF_C_NULL = 0,
ELF_C_CLR,
ELF_C_FDDONE,
ELF_C_FDREAD,
ELF_C_RDWR,
ELF_C_READ,
ELF_C_SET,
ELF_C_WRITE,
ELF_C_NUM
} Elf_Cmd;
typedef struct _Elf_Data {
uint64_t d_align;
void *d_buf;
uint64_t d_off;
uint64_t d_size;
Elf_Type d_type;
unsigned int d_version;
} Elf_Data;
typedef struct {
time_t ar_date;
char *ar_name;
gid_t ar_gid;
mode_t ar_mode;
char *ar_rawname;
size_t ar_size;
uid_t ar_uid;
unsigned int ar_flags;
} Elf_Arhdr;
typedef struct {
off_t as_off;
unsigned long as_hash;
char *as_name;
} Elf_Arsym;
enum Elf_Error {
ELF_E_NONE,
ELF_E_ARCHIVE,
ELF_E_ARGUMENT,
ELF_E_CLASS,
ELF_E_DATA,
ELF_E_HEADER,
ELF_E_IO,
ELF_E_LAYOUT,
ELF_E_MODE,
ELF_E_RANGE,
ELF_E_RESOURCE,
ELF_E_SECTION,
ELF_E_SEQUENCE,
ELF_E_UNIMPL,
ELF_E_VERSION,
ELF_E_NUM
};
#define ELF_F_LAYOUT 0x001U
#define ELF_F_DIRTY 0x002U
#ifdef __cplusplus
extern "C" {
#endif
static
Elf *elf_begin(int _fd, Elf_Cmd _cmd, Elf *_elf);
static
int elf_end(Elf *_elf);
static
const char *elf_errmsg(int _error);
static
int elf_errno(void);
static
Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *);
static
char *elf_strptr(Elf *_elf, size_t _section, size_t _offset);
static
unsigned int elf_version(unsigned int _version);
static
Elf_Scn *elf_nextscn(Elf *_elf, Elf_Scn *_scn);
#ifdef __cplusplus
}
#endif
typedef Elf64_Shdr GElf_Shdr;
typedef Elf64_Sym GElf_Sym;
#ifdef __cplusplus
extern "C" {
#endif
static
GElf_Shdr *gelf_getshdr(Elf_Scn *_scn, GElf_Shdr *_dst);
static
GElf_Sym *gelf_getsym(Elf_Data *_src, int _index, GElf_Sym *_dst);
#ifdef __cplusplus
}
#endif
#define LIBELF_MSG_SIZE 256
struct _libelf_globals {
int libelf_arch;
unsigned int libelf_byteorder;
int libelf_class;
int libelf_error;
int libelf_fillchar;
unsigned int libelf_version;
unsigned char libelf_msg[LIBELF_MSG_SIZE];
};
#if 0
extern struct _libelf_globals _libelf;
#endif
#define LIBELF_PRIVATE(N) (_libelf.libelf_##N)
#define LIBELF_ELF_ERROR_MASK 0xFF
#define LIBELF_OS_ERROR_SHIFT 8
#define LIBELF_ERROR(E, O) (((E) & LIBELF_ELF_ERROR_MASK) | \
((O) << LIBELF_OS_ERROR_SHIFT))
#define LIBELF_SET_ERROR(E, O) do { \
LIBELF_PRIVATE(error) = LIBELF_ERROR(ELF_E_##E, (O)); \
} while (0)
#define LIBELF_F_DATA_MALLOCED 0x040000U
#define LIBELF_F_RAWFILE_MALLOC 0x080000U
#define LIBELF_F_RAWFILE_MMAP 0x100000U
#define LIBELF_F_SHDRS_LOADED 0x200000U
#define LIBELF_F_SPECIAL_FILE 0x400000U
struct _Elf {
int e_activations;
unsigned int e_byteorder;
int e_class;
Elf_Cmd e_cmd;
int e_fd;
unsigned int e_flags;
Elf_Kind e_kind;
Elf *e_parent;
unsigned char *e_rawfile;
size_t e_rawsize;
unsigned int e_version;
union {
Elf_Arhdr *e_arhdr;
unsigned char *e_rawhdr;
} e_hdr;
union {
struct {
off_t e_next;
int e_nchildren;
unsigned char *e_rawstrtab;
size_t e_rawstrtabsz;
unsigned char *e_rawsymtab;
size_t e_rawsymtabsz;
Elf_Arsym *e_symtab;
size_t e_symtabsz;
} e_ar;
struct {
union {
#if 0
Elf32_Ehdr *e_ehdr32;
#endif
Elf64_Ehdr *e_ehdr64;
} e_ehdr;
union {
#if 0
Elf32_Phdr *e_phdr32;
#endif
Elf64_Phdr *e_phdr64;
} e_phdr;
STAILQ_HEAD(, _Elf_Scn) e_scn;
size_t e_nphdr;
size_t e_nscn;
size_t e_strndx;
} e_elf;
} e_u;
};
struct _Libelf_Data {
Elf_Data d_data;
Elf_Scn *d_scn;
unsigned int d_flags;
STAILQ_ENTRY(_Libelf_Data) d_next;
};
struct _Elf_Scn {
union {
#if 0
Elf32_Shdr s_shdr32;
#endif
Elf64_Shdr s_shdr64;
} s_shdr;
STAILQ_HEAD(, _Libelf_Data) s_data;
STAILQ_HEAD(, _Libelf_Data) s_rawdata;
STAILQ_ENTRY(_Elf_Scn) s_next;
struct _Elf *s_elf;
unsigned int s_flags;
size_t s_ndx;
uint64_t s_offset;
uint64_t s_rawoff;
uint64_t s_size;
};
enum {
ELF_TOFILE,
ELF_TOMEMORY
};
static struct _libelf_globals _libelf = {
.libelf_arch = LIBELF_ARCH,
.libelf_byteorder = LIBELF_BYTEORDER,
.libelf_class = LIBELF_CLASS,
.libelf_error = 0,
.libelf_fillchar = 0,
.libelf_version = EV_NONE
};
struct msize {
size_t msz64;
};
static struct msize msize[ELF_T_NUM] = {
[ELF_T_ADDR] = { .msz64 = sizeof(Elf64_Addr) },
[ELF_T_BYTE] = { .msz64 = 1 },
[ELF_T_CAP] = { .msz64 = sizeof(Elf64_Cap) },
[ELF_T_DYN] = { .msz64 = sizeof(Elf64_Dyn) },
[ELF_T_EHDR] = { .msz64 = sizeof(Elf64_Ehdr) },
[ELF_T_GNUHASH] = { .msz64 = 1 },
[ELF_T_HALF] = { .msz64 = sizeof(Elf64_Half) },
[ELF_T_LWORD] = { .msz64 = sizeof(Elf64_Lword) },
[ELF_T_MOVE] = { .msz64 = sizeof(Elf64_Move) },
[ELF_T_MOVEP] = { .msz64 = 0 },
[ELF_T_NOTE] = { .msz64 = 1 },
[ELF_T_OFF] = { .msz64 = sizeof(Elf64_Off) },
[ELF_T_PHDR] = { .msz64 = sizeof(Elf64_Phdr) },
[ELF_T_REL] = { .msz64 = sizeof(Elf64_Rel) },
[ELF_T_RELA] = { .msz64 = sizeof(Elf64_Rela) },
[ELF_T_SHDR] = { .msz64 = sizeof(Elf64_Shdr) },
[ELF_T_SWORD] = { .msz64 = sizeof(Elf64_Sword) },
[ELF_T_SXWORD] = { .msz64 = sizeof(Elf64_Sxword) },
[ELF_T_SYMINFO] = { .msz64 = sizeof(Elf64_Syminfo) },
[ELF_T_SYM] = { .msz64 = sizeof(Elf64_Sym) },
[ELF_T_VDEF] = { .msz64 = 1 },
[ELF_T_VNEED] = { .msz64 = 1 },
[ELF_T_WORD] = { .msz64 = sizeof(Elf64_Word) },
[ELF_T_XWORD] = { .msz64 = sizeof(Elf64_Xword) },
};
static size_t
_libelf_msize(Elf_Type t, int elfclass, unsigned int version)
{
size_t sz;
assert( elfclass == ELFCLASS64);
assert((signed) t >= ELF_T_FIRST && t <= ELF_T_LAST);
if (version != EV_CURRENT) {
LIBELF_SET_ERROR(VERSION, 0);
return (0);
}
sz = msize[t].msz64;
return (sz);
}
struct tfsize {
size_t fsz64;
};
static struct tfsize tfsize[ELF_T_NUM] = {
[ELF_T_ADDR] = { .fsz64 = sizeof(Elf64_Addr) },
[ELF_T_BYTE] = { .fsz64 = 1 },
[ELF_T_CAP] = { .fsz64 = sizeof(Elf64_Xword)+sizeof(Elf64_Xword)+0 },
[ELF_T_DYN] = { .fsz64 = sizeof(Elf64_Sxword)+sizeof(Elf64_Xword)+0 },
[ELF_T_EHDR] = { .fsz64 = EI_NIDENT
+sizeof(Elf64_Half)+sizeof(Elf64_Half)
+sizeof(Elf64_Word)+sizeof(Elf64_Addr)
+sizeof(Elf64_Off)+ sizeof(Elf64_Off)
+sizeof(Elf64_Word)+sizeof(Elf64_Half)
+sizeof(Elf64_Half)+sizeof(Elf64_Half)
+sizeof(Elf64_Half)+sizeof(Elf64_Half)
+sizeof(Elf64_Half)+0 },
[ELF_T_GNUHASH] = { .fsz64 = 1 },
[ELF_T_HALF] = { .fsz64 = sizeof(Elf64_Half) },
[ELF_T_LWORD] = { .fsz64 = sizeof(Elf64_Lword) },
[ELF_T_MOVE] = { .fsz64 = sizeof(Elf64_Lword)+sizeof(Elf64_Xword)
+sizeof(Elf64_Xword)+sizeof(Elf64_Half)
+sizeof(Elf64_Half)+0 },
[ELF_T_MOVEP] = { .fsz64 = 0 },
[ELF_T_NOTE] = { .fsz64 = 1 },
[ELF_T_OFF] = { .fsz64 = sizeof(Elf64_Off) },
[ELF_T_PHDR] = { .fsz64 = sizeof(Elf64_Word)+sizeof(Elf64_Word)
+sizeof(Elf64_Off)+ sizeof(Elf64_Addr)
+sizeof(Elf64_Addr)+sizeof(Elf64_Xword)
+sizeof(Elf64_Xword)+sizeof(Elf64_Xword)+0 },
[ELF_T_REL] = { .fsz64 = sizeof(Elf64_Addr)+sizeof(Elf64_Xword)+0 },
[ELF_T_RELA] = { .fsz64 = sizeof(Elf64_Addr)+sizeof(Elf64_Xword)
+sizeof(Elf64_Sxword)+0 },
[ELF_T_SHDR] = { .fsz64 = sizeof(Elf64_Word)+sizeof(Elf64_Word)
+sizeof(Elf64_Xword)+sizeof(Elf64_Addr)
+sizeof(Elf64_Off)+ sizeof(Elf64_Xword)
+sizeof(Elf64_Word)+sizeof(Elf64_Word)
+sizeof(Elf64_Xword)+sizeof(Elf64_Xword)+0 },
[ELF_T_SWORD] = { .fsz64 = sizeof(Elf64_Sword) },
[ELF_T_SXWORD] = { .fsz64 = sizeof(Elf64_Sxword) },
[ELF_T_SYMINFO] = { .fsz64 = sizeof(Elf64_Half)+sizeof(Elf64_Half)+0 },
[ELF_T_SYM] = { .fsz64 = sizeof(Elf64_Word)+1+1+sizeof(Elf64_Half)
+sizeof(Elf64_Addr)+sizeof(Elf64_Xword)+0 },
[ELF_T_VDEF] = { .fsz64 = 1 },
[ELF_T_VNEED] = { .fsz64 = 1 },
[ELF_T_WORD] = { .fsz64 = sizeof(Elf64_Word) },
[ELF_T_XWORD] = { .fsz64 = sizeof(Elf64_Xword) },
};
static size_t
_libelf_fsize(Elf_Type t, int ec, unsigned int v, size_t c)
{
size_t sz;
sz = 0;
if (v != EV_CURRENT)
LIBELF_SET_ERROR(VERSION, 0);
else if ((int) t < ELF_T_FIRST || t > ELF_T_LAST)
LIBELF_SET_ERROR(ARGUMENT, 0);
else {
sz = ec == ELFCLASS64 ? tfsize[t].fsz64 : 0;
if (sz == 0)
LIBELF_SET_ERROR(UNIMPL, 0);
}
return (sz*c);
}
static size_t
elf64_fsize(Elf_Type t, size_t c, unsigned int v)
{
return (_libelf_fsize(t, ELFCLASS64, v, c));
}
static Elf *
_libelf_allocate_elf(void)
{
Elf *e;
if ((e = malloc(sizeof(*e))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, errno);
return NULL;
}
e->e_activations = 1;
e->e_hdr.e_rawhdr = NULL;
e->e_byteorder = ELFDATANONE;
e->e_class = ELFCLASSNONE;
e->e_cmd = ELF_C_NULL;
e->e_fd = -1;
e->e_flags = 0;
e->e_kind = ELF_K_NONE;
e->e_parent = NULL;
e->e_rawfile = NULL;
e->e_rawsize = 0;
e->e_version = LIBELF_PRIVATE(version);
(void) memset(&e->e_u, 0, sizeof(e->e_u));
return (e);
}
static void
_libelf_init_elf(Elf *e, Elf_Kind kind)
{
assert(e != NULL);
assert(e->e_kind == ELF_K_NONE);
e->e_kind = kind;
switch (kind) {
case ELF_K_ELF:
STAILQ_INIT(&e->e_u.e_elf.e_scn);
break;
default:
break;
}
}
#define FREE(P) do { \
if (P) \
free(P); \
} while (0)
static Elf *
_libelf_release_elf(Elf *e)
{
#if 0
Elf_Arhdr *arh;
#endif
switch (e->e_kind) {
#if 0
case ELF_K_AR:
FREE(e->e_u.e_ar.e_symtab);
break;
#endif
case ELF_K_ELF:
switch (e->e_class) {
#if 0
case ELFCLASS32:
FREE(e->e_u.e_elf.e_ehdr.e_ehdr32);
FREE(e->e_u.e_elf.e_phdr.e_phdr32);
break;
#endif
case ELFCLASS64:
FREE(e->e_u.e_elf.e_ehdr.e_ehdr64);
FREE(e->e_u.e_elf.e_phdr.e_phdr64);
break;
}
assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
#if 0
if (e->e_flags & LIBELF_F_AR_HEADER) {
arh = e->e_hdr.e_arhdr;
FREE(arh->ar_name);
FREE(arh->ar_rawname);
free(arh);
}
#endif
break;
default:
break;
}
free(e);
return (NULL);
}
#undef FREE
static struct _Libelf_Data *
_libelf_allocate_data(Elf_Scn *s)
{
struct _Libelf_Data *d;
if ((d = calloc((size_t) 1, sizeof(*d))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
return (NULL);
}
d->d_scn = s;
return (d);
}
static struct _Libelf_Data *
_libelf_release_data(struct _Libelf_Data *d)
{
if (d->d_flags & LIBELF_F_DATA_MALLOCED)
free(d->d_data.d_buf);
free(d);
return (NULL);
}
static Elf_Scn *
_libelf_allocate_scn(Elf *e, size_t ndx)
{
Elf_Scn *s;
if ((s = calloc((size_t) 1, sizeof(Elf_Scn))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, errno);
return (NULL);
}
s->s_elf = e;
s->s_ndx = ndx;
STAILQ_INIT(&s->s_data);
STAILQ_INIT(&s->s_rawdata);
STAILQ_INSERT_TAIL(&e->e_u.e_elf.e_scn, s, s_next);
return (s);
}
static Elf_Scn *
_libelf_release_scn(Elf_Scn *s)
{
Elf *e;
struct _Libelf_Data *d, *td;
assert(s != NULL);
STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
STAILQ_REMOVE(&s->s_data, d, _Libelf_Data, d_next);
d = _libelf_release_data(d);
}
STAILQ_FOREACH_SAFE(d, &s->s_rawdata, d_next, td) {
assert((d->d_flags & LIBELF_F_DATA_MALLOCED) == 0);
STAILQ_REMOVE(&s->s_rawdata, d, _Libelf_Data, d_next);
d = _libelf_release_data(d);
}
e = s->s_elf;
assert(e != NULL);
STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, s_next);
free(s);
return (NULL);
}
static int
_libelf_xlate_shtype(uint32_t sht)
{
switch (sht) {
case SHT_DYNAMIC:
return (ELF_T_DYN);
case SHT_DYNSYM:
return (ELF_T_SYM);
case SHT_FINI_ARRAY:
return (ELF_T_ADDR);
case SHT_GNU_HASH:
return (ELF_T_GNUHASH);
case SHT_GNU_LIBLIST:
return (ELF_T_WORD);
case SHT_GROUP:
return (ELF_T_WORD);
case SHT_HASH:
return (ELF_T_WORD);
case SHT_INIT_ARRAY:
return (ELF_T_ADDR);
case SHT_NOBITS:
return (ELF_T_BYTE);
case SHT_NOTE:
return (ELF_T_NOTE);
case SHT_PREINIT_ARRAY:
return (ELF_T_ADDR);
case SHT_PROGBITS:
return (ELF_T_BYTE);
case SHT_REL:
return (ELF_T_REL);
case SHT_RELA:
return (ELF_T_RELA);
case SHT_STRTAB:
return (ELF_T_BYTE);
case SHT_SYMTAB:
return (ELF_T_SYM);
case SHT_SYMTAB_SHNDX:
return (ELF_T_WORD);
case SHT_SUNW_dof:
return (ELF_T_BYTE);
case SHT_SUNW_move:
return (ELF_T_MOVE);
case SHT_SUNW_syminfo:
return (ELF_T_SYMINFO);
case SHT_SUNW_verdef:
return (ELF_T_VDEF);
case SHT_SUNW_verneed:
return (ELF_T_VNEED);
case SHT_SUNW_versym:
return (ELF_T_HALF);
default:
if (sht >= SHT_LOOS && sht <= SHT_HIUSER)
return (ELF_T_BYTE);
return (-1);
}
}
#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_SWORD(X) _SWAP_WORD(X, Elf64_Sword)
#define SWAP_WORD(X) _SWAP_WORD(X, Elf64_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)
#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_SWORD(P,X) _READ_WORD(P, X, Elf64_Sword)
#define READ_WORD(P,X) _READ_WORD(P, X, Elf64_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))
static int
_libelf_cvt_ADDR64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Addr t, *d = (Elf64_Addr *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Addr))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_ADDR64(src,t);
SWAP_ADDR64(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_CAP64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Cap t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_CAP, (size_t) 1, EV_CURRENT);
d = ((Elf64_Cap *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Cap))
return (0);
while (count--) {
s = s0;
READ_XWORD(s,t.c_tag);
READ_XWORD(s,t.c_un.c_val);
if (byteswap) {
SWAP_XWORD(t.c_tag);
SWAP_XWORD(t.c_un.c_val);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_DYN64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Dyn t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_DYN, (size_t) 1, EV_CURRENT);
d = ((Elf64_Dyn *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Dyn))
return (0);
while (count--) {
s = s0;
READ_SXWORD(s,t.d_tag);
READ_XWORD(s,t.d_un.d_ptr);
if (byteswap) {
SWAP_SXWORD(t.d_tag);
SWAP_XWORD(t.d_un.d_ptr);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_EHDR64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Ehdr t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_EHDR, (size_t) 1, EV_CURRENT);
d = ((Elf64_Ehdr *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Ehdr))
return (0);
while (count--) {
s = s0;
READ_IDENT(s,t.e_ident);
READ_HALF(s,t.e_type);
READ_HALF(s,t.e_machine);
READ_WORD(s,t.e_version);
READ_ADDR64(s,t.e_entry);
READ_OFF64(s,t.e_phoff);
READ_OFF64(s,t.e_shoff);
READ_WORD(s,t.e_flags);
READ_HALF(s,t.e_ehsize);
READ_HALF(s,t.e_phentsize);
READ_HALF(s,t.e_phnum);
READ_HALF(s,t.e_shentsize);
READ_HALF(s,t.e_shnum);
READ_HALF(s,t.e_shstrndx);
if (byteswap) {
SWAP_IDENT(t.e_ident);
SWAP_HALF(t.e_type);
SWAP_HALF(t.e_machine);
SWAP_WORD(t.e_version);
SWAP_ADDR64(t.e_entry);
SWAP_OFF64(t.e_phoff);
SWAP_OFF64(t.e_shoff);
SWAP_WORD(t.e_flags);
SWAP_HALF(t.e_ehsize);
SWAP_HALF(t.e_phentsize);
SWAP_HALF(t.e_phnum);
SWAP_HALF(t.e_shentsize);
SWAP_HALF(t.e_shnum);
SWAP_HALF(t.e_shstrndx);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_HALF_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Half t, *d = (Elf64_Half *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Half))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_HALF(src,t);
SWAP_HALF(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_LWORD_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Lword t, *d = (Elf64_Lword *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Lword))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_LWORD(src,t);
SWAP_LWORD(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_MOVE64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Move t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_MOVE, (size_t) 1, EV_CURRENT);
d = ((Elf64_Move *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Move))
return (0);
while (count--) {
s = s0;
READ_LWORD(s,t.m_value);
READ_XWORD(s,t.m_info);
READ_XWORD(s,t.m_poffset);
READ_HALF(s,t.m_repeat);
READ_HALF(s,t.m_stride);
if (byteswap) {
SWAP_LWORD(t.m_value);
SWAP_XWORD(t.m_info);
SWAP_XWORD(t.m_poffset);
SWAP_HALF(t.m_repeat);
SWAP_HALF(t.m_stride);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_OFF64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Off t, *d = (Elf64_Off *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Off))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_OFF64(src,t);
SWAP_OFF64(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_PHDR64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Phdr t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_PHDR, (size_t) 1, EV_CURRENT);
d = ((Elf64_Phdr *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Phdr))
return (0);
while (count--) {
s = s0;
READ_WORD(s,t.p_type);
READ_WORD(s,t.p_flags);
READ_OFF64(s,t.p_offset);
READ_ADDR64(s,t.p_vaddr);
READ_ADDR64(s,t.p_paddr);
READ_XWORD(s,t.p_filesz);
READ_XWORD(s,t.p_memsz);
READ_XWORD(s,t.p_align);
if (byteswap) {
SWAP_WORD(t.p_type);
SWAP_WORD(t.p_flags);
SWAP_OFF64(t.p_offset);
SWAP_ADDR64(t.p_vaddr);
SWAP_ADDR64(t.p_paddr);
SWAP_XWORD(t.p_filesz);
SWAP_XWORD(t.p_memsz);
SWAP_XWORD(t.p_align);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_REL64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Rel t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_REL, (size_t) 1, EV_CURRENT);
d = ((Elf64_Rel *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Rel))
return (0);
while (count--) {
s = s0;
READ_ADDR64(s,t.r_offset);
READ_XWORD(s,t.r_info);
if (byteswap) {
SWAP_ADDR64(t.r_offset);
SWAP_XWORD(t.r_info);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_RELA64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Rela t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_RELA, (size_t) 1, EV_CURRENT);
d = ((Elf64_Rela *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Rela))
return (0);
while (count--) {
s = s0;
READ_ADDR64(s,t.r_offset);
READ_XWORD(s,t.r_info);
READ_SXWORD(s,t.r_addend);
if (byteswap) {
SWAP_ADDR64(t.r_offset);
SWAP_XWORD(t.r_info);
SWAP_SXWORD(t.r_addend);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_SHDR64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Shdr t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_SHDR, (size_t) 1, EV_CURRENT);
d = ((Elf64_Shdr *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Shdr))
return (0);
while (count--) {
s = s0;
READ_WORD(s,t.sh_name);
READ_WORD(s,t.sh_type);
READ_XWORD(s,t.sh_flags);
READ_ADDR64(s,t.sh_addr);
READ_OFF64(s,t.sh_offset);
READ_XWORD(s,t.sh_size);
READ_WORD(s,t.sh_link);
READ_WORD(s,t.sh_info);
READ_XWORD(s,t.sh_addralign);
READ_XWORD(s,t.sh_entsize);
if (byteswap) {
SWAP_WORD(t.sh_name);
SWAP_WORD(t.sh_type);
SWAP_XWORD(t.sh_flags);
SWAP_ADDR64(t.sh_addr);
SWAP_OFF64(t.sh_offset);
SWAP_XWORD(t.sh_size);
SWAP_WORD(t.sh_link);
SWAP_WORD(t.sh_info);
SWAP_XWORD(t.sh_addralign);
SWAP_XWORD(t.sh_entsize);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_SWORD_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Sword t, *d = (Elf64_Sword *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Sword))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_SWORD(src,t);
SWAP_SWORD(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_SXWORD_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Sxword t, *d = (Elf64_Sxword *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Sxword))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_SXWORD(src,t);
SWAP_SXWORD(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_SYMINFO64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Syminfo t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_SYMINFO, (size_t) 1, EV_CURRENT);
d = ((Elf64_Syminfo *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Syminfo))
return (0);
while (count--) {
s = s0;
READ_HALF(s,t.si_boundto);
READ_HALF(s,t.si_flags);
if (byteswap) {
SWAP_HALF(t.si_boundto);
SWAP_HALF(t.si_flags);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_SYM64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Sym t, *d;
unsigned char *s,*s0;
size_t fsz;
fsz = elf64_fsize(ELF_T_SYM, (size_t) 1, EV_CURRENT);
d = ((Elf64_Sym *) (uintptr_t) dst) + (count - 1);
s0 = src + (count - 1) * fsz;
if (dsz < count * sizeof(Elf64_Sym))
return (0);
while (count--) {
s = s0;
READ_WORD(s,t.st_name);
READ_BYTE(s,t.st_info);
READ_BYTE(s,t.st_other);
READ_HALF(s,t.st_shndx);
READ_ADDR64(s,t.st_value);
READ_XWORD(s,t.st_size);
if (byteswap) {
SWAP_WORD(t.st_name);
SWAP_BYTE(t.st_info);
SWAP_BYTE(t.st_other);
SWAP_HALF(t.st_shndx);
SWAP_ADDR64(t.st_value);
SWAP_XWORD(t.st_size);
}
*d-- = t; s0 -= fsz;
}
return (1);
}
static int
_libelf_cvt_WORD_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Word t, *d = (Elf64_Word *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Word))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_WORD(src,t);
SWAP_WORD(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_XWORD_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Xword t, *d = (Elf64_Xword *) (uintptr_t) dst;
size_t c;
if (dsz < count * sizeof(Elf64_Xword))
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count * sizeof(*d));
return (1);
}
for (c = 0; c < count; c++) {
READ_XWORD(src,t);
SWAP_XWORD(t);
*d++ = t;
}
return (1);
}
static int
_libelf_cvt_VDEF64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Verdef t, *dp;
Elf64_Verdaux a, *ap;
const size_t verfsz = 20;
const size_t auxfsz = 8;
const size_t vermsz = sizeof(Elf64_Verdef);
const size_t auxmsz = sizeof(Elf64_Verdaux);
unsigned char * const dstend = dst + dsz;
unsigned char * const srcend = src + count;
unsigned char *dstaux, *s, *srcaux, *stmp;
Elf64_Word aux, anext, cnt, vnext;
for (stmp = src, vnext = ~0U;
vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
stmp += vnext, dst += vnext) {
s = stmp;
READ_HALF(s,t.vd_version);
READ_HALF(s,t.vd_flags);
READ_HALF(s,t.vd_ndx);
READ_HALF(s,t.vd_cnt);
READ_WORD(s,t.vd_hash);
READ_WORD(s,t.vd_aux);
READ_WORD(s,t.vd_next);
if (byteswap) {
SWAP_HALF(t.vd_version);
SWAP_HALF(t.vd_flags);
SWAP_HALF(t.vd_ndx);
SWAP_HALF(t.vd_cnt);
SWAP_WORD(t.vd_hash);
SWAP_WORD(t.vd_aux);
SWAP_WORD(t.vd_next);
}
dp = (Elf64_Verdef *) (uintptr_t) dst;
*dp = t;
aux = t.vd_aux;
cnt = t.vd_cnt;
vnext = t.vd_next;
if (aux < vermsz)
return (0);
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;
READ_WORD(s,a.vda_name);
READ_WORD(s,a.vda_next);
if (byteswap) {
SWAP_WORD(a.vda_name);
SWAP_WORD(a.vda_next);
}
anext = a.vda_next;
ap = ((Elf64_Verdaux *) (uintptr_t) dstaux);
*ap = a;
}
if (anext || cnt)
return (0);
}
if (vnext)
return (0);
return (1);
}
static int
_libelf_cvt_VNEED64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
size_t count, int byteswap)
{
Elf64_Verneed t, *dp;
Elf64_Vernaux a, *ap;
const size_t verfsz = 16;
const size_t auxfsz = 16;
const size_t vermsz = sizeof(Elf64_Verneed);
const size_t auxmsz = sizeof(Elf64_Vernaux);
unsigned char * const dstend = dst + dsz;
unsigned char * const srcend = src + count;
unsigned char *dstaux, *s, *srcaux, *stmp;
Elf64_Word aux, anext, cnt, vnext;
for (stmp = src, vnext = ~0U;
vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
stmp += vnext, dst += vnext) {
s = stmp;
READ_HALF(s,t.vn_version);
READ_HALF(s,t.vn_cnt);
READ_WORD(s,t.vn_file);
READ_WORD(s,t.vn_aux);
READ_WORD(s,t.vn_next);
if (byteswap) {
SWAP_HALF(t.vn_version);
SWAP_HALF(t.vn_cnt);
SWAP_WORD(t.vn_file);
SWAP_WORD(t.vn_aux);
SWAP_WORD(t.vn_next);
}
dp = (Elf64_Verneed *) (uintptr_t) dst;
*dp = t;
aux = t.vn_aux;
cnt = t.vn_cnt;
vnext = t.vn_next;
if (aux < vermsz)
return (0);
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;
READ_WORD(s,a.vna_hash);
READ_HALF(s,a.vna_flags);
READ_HALF(s,a.vna_other);
READ_WORD(s,a.vna_name);
READ_WORD(s,a.vna_next);
if (byteswap) {
SWAP_WORD(a.vna_hash);
SWAP_HALF(a.vna_flags);
SWAP_HALF(a.vna_other);
SWAP_WORD(a.vna_name);
SWAP_WORD(a.vna_next);
}
anext = a.vna_next;
ap = ((Elf64_Vernaux *) (uintptr_t) dstaux);
*ap = a;
}
if (anext || cnt)
return (0);
}
if (vnext)
return (0);
return (1);
}
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);
}
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);
if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
return (0);
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);
}
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;
for (n = 0; n < maskwords; n++) {
READ_XWORD(src, t64);
if (byteswap)
SWAP_XWORD(t64);
bloom64[n] = t64;
}
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);
dsz -= sz;
srcsz -= sz;
if (dsz < srcsz)
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_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)
return (0);
hdrsz = 3 * sizeof(uint32_t);
if (count < hdrsz)
return (0);
if (!byteswap) {
(void) memcpy(dst, src, count);
return (1);
}
while (count > hdrsz) {
READ_WORD(src, namesz);
READ_WORD(src, descsz);
READ_WORD(src, type);
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;
dsz -= sizeof(Elf_Note);
dst += sizeof(Elf_Note);
count -= hdrsz;
ROUNDUP2(namesz, 4U);
ROUNDUP2(descsz, 4U);
sz = namesz + descsz;
if (count < sz || dsz < sz)
return (0);
(void) memcpy(dst, src, sz);
src += sz;
dst += sz;
count -= sz;
dsz -= 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] = {
[ELF_T_ADDR] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_ADDR64_tom },
[ELF_T_CAP] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_CAP64_tom },
[ELF_T_DYN] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_DYN64_tom },
[ELF_T_EHDR] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_EHDR64_tom },
[ELF_T_GNUHASH] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_GNUHASH64_tom },
[ELF_T_HALF] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_HALF_tom },
[ELF_T_LWORD] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_LWORD_tom },
[ELF_T_MOVE] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_MOVE64_tom },
[ELF_T_OFF] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_OFF64_tom },
[ELF_T_PHDR] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_PHDR64_tom },
[ELF_T_REL] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_REL64_tom },
[ELF_T_RELA] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_RELA64_tom },
[ELF_T_SHDR] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_SHDR64_tom },
[ELF_T_SWORD] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_SWORD_tom },
[ELF_T_SXWORD] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_SXWORD_tom },
[ELF_T_SYMINFO] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_SYMINFO64_tom },
[ELF_T_SYM] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_SYM64_tom },
[ELF_T_VDEF] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_VDEF64_tom },
[ELF_T_VNEED] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_VNEED64_tom },
[ELF_T_WORD] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_WORD_tom },
[ELF_T_XWORD] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_XWORD_tom },
[ELF_T_BYTE] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_BYTE_tox },
[ELF_T_NOTE] = { .tof32 = NULL, .tom32 = NULL, .tof64 = NULL,
.tom64 = _libelf_cvt_NOTE_tom }
};
static int (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
(unsigned char *_dst, size_t dsz, unsigned char *_src, size_t _cnt,
int _byteswap)
{
assert( elfclass == ELFCLASS64);
assert( direction == ELF_TOMEMORY);
if (t >= ELF_T_NUM ||
( elfclass != ELFCLASS64) ||
( direction != ELF_TOMEMORY))
return (NULL);
#if 1
return cvt[t].tom64;
#else
return ((elfclass == ELFCLASS32) ?
(direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
(direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
#endif
}
static int
_libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
uint16_t strndx)
{
Elf_Scn *scn;
size_t fsz;
int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s,
size_t _c, int _swap);
uint32_t shtype;
assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1);
assert(fsz > 0);
if (e->e_rawsize < shoff + fsz) {
LIBELF_SET_ERROR(HEADER, 0);
return (0);
}
if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL)
return (0);
xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
(*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr),
(unsigned char *) e->e_rawfile + shoff, (size_t) 1,
e->e_byteorder != LIBELF_PRIVATE(byteorder));
#define GET_SHDR_MEMBER(M) ( \
scn->s_shdr.s_shdr64.M)
if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) {
LIBELF_SET_ERROR(SECTION, 0);
return (0);
}
e->e_u.e_elf.e_nscn = (size_t) GET_SHDR_MEMBER(sh_size);
e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum :
GET_SHDR_MEMBER(sh_info);
e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx :
GET_SHDR_MEMBER(sh_link);
#undef GET_SHDR_MEMBER
return (1);
}
#define EHDR_INIT(E,SZ) do { \
Elf##SZ##_Ehdr *eh = (E); \
eh->e_ident[EI_MAG0] = ELFMAG0; \
eh->e_ident[EI_MAG1] = ELFMAG1; \
eh->e_ident[EI_MAG2] = ELFMAG2; \
eh->e_ident[EI_MAG3] = ELFMAG3; \
eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \
eh->e_ident[EI_DATA] = ELFDATANONE; \
eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version) & 0xFFU; \
eh->e_machine = EM_NONE; \
eh->e_type = ELF_K_NONE; \
eh->e_version = LIBELF_PRIVATE(version); \
} while (0)
static void *
_libelf_ehdr(Elf *e, int ec, int allocate)
{
void *ehdr;
size_t fsz, msz;
uint16_t phnum, shnum, strndx;
uint64_t shoff;
int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s,
size_t _c, int _swap);
assert(ec == ELFCLASS32 || ec == ELFCLASS64);
if (e == NULL || e->e_kind != ELF_K_ELF) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if (e->e_class != ELFCLASSNONE && e->e_class != ec) {
LIBELF_SET_ERROR(CLASS, 0);
return (NULL);
}
if (e->e_version != EV_CURRENT) {
LIBELF_SET_ERROR(VERSION, 0);
return (NULL);
}
if (e->e_class == ELFCLASSNONE)
e->e_class = ec;
#if 0
if (ec == ELFCLASS32)
ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32;
else
#endif
ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64;
if (ehdr != NULL)
return (ehdr);
fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) {
LIBELF_SET_ERROR(HEADER, 0);
return (NULL);
}
msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT);
assert(msz > 0);
if ((ehdr = calloc((size_t) 1, msz)) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
return (NULL);
}
#if 0
if (ec == ELFCLASS32) {
e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr;
EHDR_INIT(ehdr,32);
} else
#endif
{
e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr;
EHDR_INIT(ehdr,64);
}
if (allocate)
e->e_flags |= ELF_F_DIRTY;
if (e->e_cmd == ELF_C_WRITE)
return (ehdr);
xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec);
(*xlator)((unsigned char*) ehdr, msz, e->e_rawfile, (size_t) 1,
e->e_byteorder != LIBELF_PRIVATE(byteorder));
#if 0
if (ec == ELFCLASS32) {
phnum = ((Elf32_Ehdr *) ehdr)->e_phnum;
shnum = ((Elf32_Ehdr *) ehdr)->e_shnum;
shoff = ((Elf32_Ehdr *) ehdr)->e_shoff;
strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx;
} else
#endif
{
phnum = ((Elf64_Ehdr *) ehdr)->e_phnum;
shnum = ((Elf64_Ehdr *) ehdr)->e_shnum;
shoff = ((Elf64_Ehdr *) ehdr)->e_shoff;
strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx;
}
if (shnum >= SHN_LORESERVE ||
(shoff == 0LL && (shnum != 0 || phnum == PN_XNUM ||
strndx == SHN_XINDEX))) {
LIBELF_SET_ERROR(HEADER, 0);
return (NULL);
}
if (shnum != 0 || shoff == 0LL) {
e->e_u.e_elf.e_nphdr = phnum;
e->e_u.e_elf.e_nscn = shnum;
e->e_u.e_elf.e_strndx = strndx;
} else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0)
return (NULL);
return (ehdr);
}
static void *
_libelf_getshdr(Elf_Scn *s, int ec)
{
Elf *e;
if (s == NULL || (e = s->s_elf) == NULL ||
e->e_kind != ELF_K_ELF) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if (ec == ELFCLASSNONE)
ec = e->e_class;
if (ec != e->e_class) {
LIBELF_SET_ERROR(CLASS, 0);
return (NULL);
}
return ((void *) &s->s_shdr);
}
static int
_libelf_load_section_headers(Elf *e, void *ehdr)
{
Elf_Scn *scn;
uint64_t shoff;
#if 0
Elf32_Ehdr *eh32;
#endif
Elf64_Ehdr *eh64;
int ec, swapbytes;
unsigned char *src;
size_t fsz, i, shnum;
int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s,
size_t _c, int _swap);
assert(e != NULL);
assert(ehdr != NULL);
assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0);
#define CHECK_EHDR(E,EH) do { \
if (shoff > e->e_rawsize || \
fsz != (EH)->e_shentsize || \
shnum > SIZE_MAX / fsz || \
fsz * shnum > e->e_rawsize - shoff) { \
LIBELF_SET_ERROR(HEADER, 0); \
return (0); \
} \
} while (0)
ec = e->e_class;
fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
shnum = e->e_u.e_elf.e_nscn;
#if 0
if (ec == ELFCLASS32) {
eh32 = (Elf32_Ehdr *) ehdr;
shoff = (uint64_t) eh32->e_shoff;
CHECK_EHDR(e, eh32);
} else
#endif
{
eh64 = (Elf64_Ehdr *) ehdr;
shoff = eh64->e_shoff;
CHECK_EHDR(e, eh64);
}
xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder);
src = e->e_rawfile + shoff;
i = 0;
if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) ==
STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next));
i = 1;
src += fsz;
}
for (; i < shnum; i++, src += fsz) {
if ((scn = _libelf_allocate_scn(e, i)) == NULL)
return (0);
(*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr),
src, (size_t) 1, swapbytes);
#if 0
if (ec == ELFCLASS32) {
scn->s_offset = scn->s_rawoff =
scn->s_shdr.s_shdr32.sh_offset;
scn->s_size = scn->s_shdr.s_shdr32.sh_size;
} else
#endif
{
scn->s_offset = scn->s_rawoff =
scn->s_shdr.s_shdr64.sh_offset;
scn->s_size = scn->s_shdr.s_shdr64.sh_size;
}
}
e->e_flags |= LIBELF_F_SHDRS_LOADED;
return (1);
}
static Elf_Scn *
elf_getscn(Elf *e, size_t index)
{
int ec;
void *ehdr;
Elf_Scn *s;
if (e == NULL || e->e_kind != ELF_K_ELF ||
((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
return (NULL);
if (e->e_cmd != ELF_C_WRITE &&
(e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
_libelf_load_section_headers(e, ehdr) == 0)
return (NULL);
STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next)
if (s->s_ndx == index)
return (s);
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
static Elf *
_libelf_memory(unsigned char *image, size_t sz, int reporterror)
{
Elf *e;
int e_class;
enum Elf_Error error;
unsigned int e_byteorder, e_version;
assert(image != NULL);
assert(sz > 0);
if ((e = _libelf_allocate_elf()) == NULL)
return (NULL);
e->e_cmd = ELF_C_READ;
e->e_rawfile = image;
e->e_rawsize = sz;
#undef LIBELF_IS_ELF
#define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \
(P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \
(P)[EI_MAG3] == ELFMAG3)
if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) {
e_byteorder = image[EI_DATA];
e_class = image[EI_CLASS];
e_version = image[EI_VERSION];
error = ELF_E_NONE;
if (e_version > EV_CURRENT)
error = ELF_E_VERSION;
else if ((e_byteorder != ELFDATA2LSB && e_byteorder !=
ELFDATA2MSB) || (e_class != ELFCLASS32 && e_class !=
ELFCLASS64))
error = ELF_E_HEADER;
if (error != ELF_E_NONE) {
if (reporterror) {
LIBELF_PRIVATE(error) = LIBELF_ERROR(error, 0);
(void) _libelf_release_elf(e);
return (NULL);
}
} else {
_libelf_init_elf(e, ELF_K_ELF);
e->e_byteorder = e_byteorder;
e->e_class = e_class;
e->e_version = e_version;
}
}
#if 0
else if (sz >= SARMAG &&
strncmp((const char *) image, ARMAG, (size_t) SARMAG) == 0)
return (_libelf_ar_open(e, reporterror));
#endif
return (e);
}
#define _LIBELF_INITSIZE (64*1024)
static void *
_libelf_read_special_file(int fd, size_t *fsz)
{
ssize_t readsz;
size_t bufsz, datasz;
unsigned char *buf, *t;
datasz = 0;
readsz = 0;
bufsz = _LIBELF_INITSIZE;
if ((buf = malloc(bufsz)) == NULL)
goto resourceerror;
do {
if (datasz == bufsz) {
bufsz *= 2;
if ((t = realloc(buf, bufsz)) == NULL)
goto resourceerror;
buf = t;
}
do {
assert(bufsz - datasz > 0);
t = buf + datasz;
if ((readsz = read(fd, t, bufsz - datasz)) <= 0)
break;
datasz += (size_t) readsz;
} while (datasz < bufsz);
} while (readsz > 0);
if (readsz < 0) {
LIBELF_SET_ERROR(IO, errno);
goto error;
}
assert(readsz == 0);
if (bufsz > datasz) {
if (datasz > 0) {
if ((t = realloc(buf, datasz)) == NULL)
goto resourceerror;
buf = t;
} else {
LIBELF_SET_ERROR(ARGUMENT, 0);
free(buf);
buf = NULL;
}
}
*fsz = datasz;
return (buf);
resourceerror:
LIBELF_SET_ERROR(RESOURCE, 0);
error:
if (buf != NULL)
free(buf);
return (NULL);
}
static Elf *
_libelf_open_object(int fd, Elf_Cmd c, int reporterror)
{
Elf *e;
void *m;
mode_t mode;
size_t fsize;
struct stat sb;
unsigned int flags;
assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE);
if (fstat(fd, &sb) < 0) {
LIBELF_SET_ERROR(IO, errno);
return (NULL);
}
mode = sb.st_mode;
fsize = (size_t) sb.st_size;
if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
!S_ISSOCK(mode)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if (c == ELF_C_WRITE) {
if ((e = _libelf_allocate_elf()) != NULL) {
_libelf_init_elf(e, ELF_K_ELF);
e->e_byteorder = LIBELF_PRIVATE(byteorder);
e->e_fd = fd;
e->e_cmd = c;
if (!S_ISREG(mode))
e->e_flags |= LIBELF_F_SPECIAL_FILE;
}
return (e);
}
m = NULL;
flags = 0;
if (S_ISREG(mode)) {
if (fsize == 0) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
#if ELFTC_HAVE_MMAP
m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0);
if (m == MAP_FAILED)
m = NULL;
else
flags = LIBELF_F_RAWFILE_MMAP;
#endif
if (m == NULL) {
if ((m = malloc(fsize)) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
return (NULL);
}
if (read(fd, m, fsize) != (ssize_t) fsize) {
LIBELF_SET_ERROR(IO, errno);
free(m);
return (NULL);
}
flags = LIBELF_F_RAWFILE_MALLOC;
}
} else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL)
flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE;
else
return (NULL);
if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) {
assert((flags & LIBELF_F_RAWFILE_MALLOC) ||
(flags & LIBELF_F_RAWFILE_MMAP));
if (flags & LIBELF_F_RAWFILE_MALLOC)
free(m);
#if ELFTC_HAVE_MMAP
else
(void) munmap(m, fsize);
#endif
return (NULL);
}
#if 0
if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) {
(void) elf_end(e);
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
#endif
e->e_flags |= flags;
e->e_fd = fd;
e->e_cmd = c;
return (e);
}
static const char *_libelf_errors[] = {
#define DEFINE_ERROR(N,S) [ELF_E_##N] = S
DEFINE_ERROR(NONE, "No Error"),
DEFINE_ERROR(ARCHIVE, "Malformed ar(1) archive"),
DEFINE_ERROR(ARGUMENT, "Invalid argument"),
DEFINE_ERROR(CLASS, "ELF class mismatch"),
DEFINE_ERROR(DATA, "Invalid data buffer descriptor"),
DEFINE_ERROR(HEADER, "Missing or malformed ELF header"),
DEFINE_ERROR(IO, "I/O error"),
DEFINE_ERROR(LAYOUT, "Layout constraint violation"),
DEFINE_ERROR(MODE, "Incorrect ELF descriptor mode"),
DEFINE_ERROR(RANGE, "Value out of range of target"),
DEFINE_ERROR(RESOURCE, "Resource exhaustion"),
DEFINE_ERROR(SECTION, "Invalid section descriptor"),
DEFINE_ERROR(SEQUENCE, "API calls out of sequence"),
DEFINE_ERROR(UNIMPL, "Unimplemented feature"),
DEFINE_ERROR(VERSION, "Unknown ELF API version"),
DEFINE_ERROR(NUM, "Unknown error")
#undef DEFINE_ERROR
};
static const char *
elf_errmsg(int error)
{
int oserr;
if (error == ELF_E_NONE &&
(error = LIBELF_PRIVATE(error)) == 0)
return NULL;
else if (error == -1)
error = LIBELF_PRIVATE(error);
oserr = error >> LIBELF_OS_ERROR_SHIFT;
error &= LIBELF_ELF_ERROR_MASK;
if (error < ELF_E_NONE || error >= ELF_E_NUM)
return _libelf_errors[ELF_E_NUM];
if (oserr) {
(void) snprintf((char *) LIBELF_PRIVATE(msg),
sizeof(LIBELF_PRIVATE(msg)), "%s: %s",
_libelf_errors[error], strerror(oserr));
return (const char *)&LIBELF_PRIVATE(msg);
}
return _libelf_errors[error];
}
static int
elf_errno(void)
{
int old;
old = LIBELF_PRIVATE(error);
LIBELF_PRIVATE(error) = 0;
return (old & LIBELF_ELF_ERROR_MASK);
}
static unsigned int
elf_version(unsigned int v)
{
unsigned int old;
if ((old = LIBELF_PRIVATE(version)) == EV_NONE)
old = EV_CURRENT;
if (v == EV_NONE)
return old;
if (v > EV_CURRENT) {
LIBELF_SET_ERROR(VERSION, 0);
return EV_NONE;
}
LIBELF_PRIVATE(version) = v;
return (old);
}
static Elf *
elf_begin(int fd, Elf_Cmd c, Elf *a)
{
Elf *e;
e = NULL;
if (LIBELF_PRIVATE(version) == EV_NONE) {
LIBELF_SET_ERROR(SEQUENCE, 0);
return (NULL);
}
switch (c) {
case ELF_C_NULL:
return (NULL);
case ELF_C_WRITE:
a = NULL;
break;
case ELF_C_RDWR:
if (a != NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
case ELF_C_READ:
if (a &&
((a->e_fd != -1 && a->e_fd != fd) || c != a->e_cmd)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
break;
default:
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if (a == NULL)
e = _libelf_open_object(fd, c, 1);
#if 0
else if (a->e_kind == ELF_K_AR)
e = _libelf_ar_open_member(a->e_fd, c, a);
#endif
else
(e = a)->e_activations++;
return (e);
}
static int
elf_end(Elf *e)
{
Elf *sv;
Elf_Scn *scn, *tscn;
if (e == NULL || e->e_activations == 0)
return (0);
if (--e->e_activations > 0)
return (e->e_activations);
assert(e->e_activations == 0);
while (e && e->e_activations == 0) {
switch (e->e_kind) {
case ELF_K_AR:
if (e->e_u.e_ar.e_nchildren > 0)
return (0);
break;
case ELF_K_ELF:
STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next,
tscn)
scn = _libelf_release_scn(scn);
break;
case ELF_K_NUM:
assert(0);
default:
break;
}
if (e->e_rawfile) {
if (e->e_flags & LIBELF_F_RAWFILE_MALLOC)
free(e->e_rawfile);
#if ELFTC_HAVE_MMAP
else if (e->e_flags & LIBELF_F_RAWFILE_MMAP)
(void) munmap(e->e_rawfile, e->e_rawsize);
#endif
}
sv = e;
if ((e = e->e_parent) != NULL)
e->e_u.e_ar.e_nchildren--;
sv = _libelf_release_elf(sv);
}
return (0);
}
static GElf_Shdr *
gelf_getshdr(Elf_Scn *s, GElf_Shdr *d)
{
int ec;
void *sh;
#if 0
Elf32_Shdr *sh32;
#endif
Elf64_Shdr *sh64;
if (d == NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if ((sh = _libelf_getshdr(s, ELFCLASSNONE)) == NULL)
return (NULL);
ec = s->s_elf->e_class;
assert( ec == ELFCLASS64);
#if 0
if (ec == ELFCLASS32) {
sh32 = (Elf32_Shdr *) sh;
d->sh_name = sh32->sh_name;
d->sh_type = sh32->sh_type;
d->sh_flags = (Elf64_Xword) sh32->sh_flags;
d->sh_addr = (Elf64_Addr) sh32->sh_addr;
d->sh_offset = (Elf64_Off) sh32->sh_offset;
d->sh_size = (Elf64_Xword) sh32->sh_size;
d->sh_link = sh32->sh_link;
d->sh_info = sh32->sh_info;
d->sh_addralign = (Elf64_Xword) sh32->sh_addralign;
d->sh_entsize = (Elf64_Xword) sh32->sh_entsize;
} else
#endif
{
sh64 = (Elf64_Shdr *) sh;
*d = *sh64;
}
return (d);
}
static GElf_Sym *
gelf_getsym(Elf_Data *ed, int ndx, GElf_Sym *dst)
{
int ec;
Elf *e;
size_t msz;
Elf_Scn *scn;
uint32_t sh_type;
#if 0
Elf32_Sym *sym32;
#endif
Elf64_Sym *sym64;
struct _Libelf_Data *d;
d = (struct _Libelf_Data *) ed;
if (d == NULL || ndx < 0 || dst == NULL ||
(scn = d->d_scn) == NULL ||
(e = scn->s_elf) == NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
ec = e->e_class;
assert( ec == ELFCLASS64);
#if 0
if (ec == ELFCLASS32)
sh_type = scn->s_shdr.s_shdr32.sh_type;
else
#endif
sh_type = scn->s_shdr.s_shdr64.sh_type;
if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
msz = _libelf_msize(ELF_T_SYM, ec, e->e_version);
assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
#if 0
if (ec == ELFCLASS32) {
sym32 = (Elf32_Sym *) d->d_data.d_buf + ndx;
dst->st_name = sym32->st_name;
dst->st_value = (Elf64_Addr) sym32->st_value;
dst->st_size = (Elf64_Xword) sym32->st_size;
dst->st_info = sym32->st_info;
dst->st_other = sym32->st_other;
dst->st_shndx = sym32->st_shndx;
} else
#endif
{
sym64 = (Elf64_Sym *) d->d_data.d_buf + ndx;
*dst = *sym64;
}
return (dst);
}
static Elf_Scn *
elf_nextscn(Elf *e, Elf_Scn *s)
{
if (e == NULL || (e->e_kind != ELF_K_ELF) ||
(s && s->s_elf != e)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
return (s == NULL ? elf_getscn(e, (size_t) 1) :
STAILQ_NEXT(s, s_next));
}
static char *
elf_strptr(Elf *e, size_t scndx, size_t offset)
{
Elf_Scn *s;
Elf_Data *d;
GElf_Shdr shdr;
uint64_t alignment, count;
if (e == NULL || e->e_kind != ELF_K_ELF) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if ((s = elf_getscn(e, scndx)) == NULL ||
gelf_getshdr(s, &shdr) == NULL)
return (NULL);
if (shdr.sh_type != SHT_STRTAB ||
offset >= shdr.sh_size) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
d = NULL;
if (e->e_flags & ELF_F_LAYOUT) {
while ((d = elf_getdata(s, d)) != NULL) {
if (d->d_buf == 0 || d->d_size == 0)
continue;
if (d->d_type != ELF_T_BYTE) {
LIBELF_SET_ERROR(DATA, 0);
return (NULL);
}
if (offset >= d->d_off &&
offset < d->d_off + d->d_size)
return ((char *) d->d_buf + offset - d->d_off);
}
} else {
count = (uint64_t) 0;
while ((d = elf_getdata(s, d)) != NULL && count <= offset) {
if (d->d_buf == NULL || d->d_size == 0)
continue;
if (d->d_type != ELF_T_BYTE) {
LIBELF_SET_ERROR(DATA, 0);
return (NULL);
}
if ((alignment = d->d_align) > 1) {
if ((alignment & (alignment - 1)) != 0) {
LIBELF_SET_ERROR(DATA, 0);
return (NULL);
}
count = roundup2(count, alignment);
}
if (offset < count) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
if (offset < count + d->d_size) {
if (d->d_buf != NULL)
return ((char *) d->d_buf +
offset - count);
LIBELF_SET_ERROR(DATA, 0);
return (NULL);
}
count += d->d_size;
}
}
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
static Elf_Data *
elf_getdata(Elf_Scn *s, Elf_Data *ed)
{
Elf *e;
unsigned int sh_type;
int elfclass, elftype;
size_t count, fsz, msz;
struct _Libelf_Data *d;
uint64_t sh_align, sh_offset, sh_size;
int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s,
size_t _c, int _swap);
d = (struct _Libelf_Data *) ed;
if (s == NULL || (e = s->s_elf) == NULL ||
(d != NULL && s != d->d_scn)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
assert(e->e_kind == ELF_K_ELF);
if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL)
return (&d->d_data);
if (d != NULL)
return (&STAILQ_NEXT(d, d_next)->d_data);
if (e->e_rawfile == NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (NULL);
}
elfclass = e->e_class;
assert( elfclass == ELFCLASS64);
#if 0
if (elfclass == ELFCLASS32) {
sh_type = s->s_shdr.s_shdr32.sh_type;
sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
} else
#endif
{
sh_type = s->s_shdr.s_shdr64.sh_type;
sh_offset = s->s_shdr.s_shdr64.sh_offset;
sh_size = s->s_shdr.s_shdr64.sh_size;
sh_align = s->s_shdr.s_shdr64.sh_addralign;
}
if (sh_type == SHT_NULL) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
sh_offset + sh_size > (uint64_t) e->e_rawsize)) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
if ((fsz = ( elf64_fsize)
(elftype, (size_t) 1, e->e_version)) == 0) {
LIBELF_SET_ERROR(UNIMPL, 0);
return (NULL);
}
if (sh_size % fsz) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
if (sh_size / fsz > SIZE_MAX) {
LIBELF_SET_ERROR(RANGE, 0);
return (NULL);
}
count = (size_t) (sh_size / fsz);
msz = _libelf_msize(elftype, elfclass, e->e_version);
if (count > 0 && msz > SIZE_MAX / count) {
LIBELF_SET_ERROR(RANGE, 0);
return (NULL);
}
assert(msz > 0);
assert(count <= SIZE_MAX);
assert(msz * count <= SIZE_MAX);
if ((d = _libelf_allocate_data(s)) == NULL)
return (NULL);
d->d_data.d_buf = NULL;
d->d_data.d_off = 0;
d->d_data.d_align = sh_align;
d->d_data.d_size = msz * count;
d->d_data.d_type = elftype;
d->d_data.d_version = e->e_version;
if (sh_type == SHT_NOBITS || sh_size == 0) {
STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
return (&d->d_data);
}
if ((d->d_data.d_buf = malloc(msz * count)) == NULL) {
(void) _libelf_release_data(d);
LIBELF_SET_ERROR(RESOURCE, 0);
return (NULL);
}
d->d_flags |= LIBELF_F_DATA_MALLOCED;
xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass);
if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size,
e->e_rawfile + sh_offset, count,
e->e_byteorder != LIBELF_PRIVATE(byteorder))) {
_libelf_release_data(d);
LIBELF_SET_ERROR(DATA, 0);
return (NULL);
}
STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
return (&d->d_data);
}
#endif