Mercurial > pub > dyncall > dyncall
diff dynload/dynload_syms_elf.c @ 0:3e629dc19168
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:24:28 +0100 |
parents | |
children | 011b5e3a8548 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dynload/dynload_syms_elf.c Thu Mar 19 22:24:28 2015 +0100 @@ -0,0 +1,215 @@ +/* + + Package: dyncall + Library: dynload + File: dynload/dynload_syms_elf.c + Description: + License: + + Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, + Tassilo Philipp <tphilipp@potion-studios.com>, + Olivier Chafik <olivier.chafik@gmail.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + + +#include "../autovar/autovar_OS.h" + +/* + + dynamic symbol resolver for elf + +*/ + +#include "dynload.h" +#if defined(OS_OpenBSD) +# include <stdint.h> +# include <elf_abi.h> +#elif defined(OS_SunOS) +# include <libelf.h> +#elif defined(OS_BeOS) +# include <elf32.h> +#else +# include <elf.h> +#endif + +#if defined(__GLIBC__) +# define _GNU_SOURCE +# define __USE_GNU +#endif + +#include "dynload_alloc.h" + +#include <assert.h> +#include <fcntl.h> +#include <dlfcn.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> + +/* run-time configuration 64/32 */ +#if defined(OS_OpenBSD) +#else +# include "../autovar/autovar_ABI.h" +# ifdef ABI_ELF64 + +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Sym Elf_Sym; +# ifndef OS_SunOS +typedef Elf64_Dyn Elf_Dyn; +# endif +typedef Elf64_Sxword Elf_tag; +typedef Elf64_Addr Elf_Addr; + +# else +# if defined(OS_BeOS) +typedef struct Elf32_Ehdr Elf_Ehdr; +typedef struct Elf32_Phdr Elf_Phdr; +typedef struct Elf32_Shdr Elf_Shdr; +typedef struct Elf32_Sym Elf_Sym; +typedef struct Elf32_Dyn Elf_Dyn; +typedef Elf32_Sword Elf_tag; +typedef Elf32_Addr Elf_Addr; + +# else + +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Sym Elf_Sym; +# ifndef OS_SunOS +typedef Elf32_Dyn Elf_Dyn; +# endif +typedef Elf32_Sword Elf_tag; +typedef Elf32_Addr Elf_Addr; + +# endif +# endif +#endif + + +struct DLSyms_ +{ + const char* pStrTab; + Elf_Sym* pSymTab; + size_t strTabSize; + size_t nSymbols; + Elf_Ehdr* pElf_Ehdr; /* pointer to elf header */ + int file; /* fd of lib */ + size_t fileSize; /* filesize of open lib */ +}; + + +DLSyms* dlSymsInit(const char* libPath) +{ + unsigned char* pMem; + void* pSectionContent; + int i; + struct stat st; + Elf_Shdr* pS; + DLSyms* pSyms = (DLSyms*)dlAllocMem(sizeof(DLSyms)); + memset(pSyms, 0, sizeof(DLSyms)); + pSyms->file = open(libPath, O_RDONLY); + stat(libPath, &st); + pSyms->fileSize = st.st_size; + pSyms->pElf_Ehdr = (Elf_Ehdr*) mmap((void*) NULL, pSyms->fileSize, PROT_READ, MAP_SHARED, pSyms->file, 0); + +#ifdef ABI_ELF32 + assert(pSyms->pElf_Ehdr->e_ident[EI_CLASS] == ELFCLASS32); +#else + assert(pSyms->pElf_Ehdr->e_ident[EI_CLASS] == ELFCLASS64); +#endif + + assert(pSyms->pElf_Ehdr->e_phoff > 0); + assert(pSyms->pElf_Ehdr->e_shoff > 0); + + + pMem = (unsigned char*)pSyms->pElf_Ehdr; + + /* traverse section headers */ + pS = (Elf_Shdr*) ( pMem + pSyms->pElf_Ehdr->e_shoff ); + /* skip section 0 which is always zero due to the Elf standard. */ + for (i = 1; i < pSyms->pElf_Ehdr->e_shnum; i++) + { + Elf_Shdr* pSection = &pS[i]; + pSectionContent = ((char*)pMem) + pSection->sh_offset; + switch (pSection->sh_type) + { + case SHT_DYNSYM: + if (!pSyms->pSymTab) { + pSyms->pSymTab = (Elf_Sym*)pSectionContent; + pSyms->nSymbols = pSection->sh_size / pSection->sh_entsize; + } + break; + case SHT_STRTAB: + // Do not trust pSyms->pElf_Ehdr->e_shstrndx! + if (!pSyms->pStrTab) { + pSyms->pStrTab = (const char*)pSectionContent; + pSyms->strTabSize = pSection->sh_size; + } + break; + } + if (pSyms->pSymTab && pSyms->pStrTab) + break; + } + return pSyms; +} + + +void dlSymsCleanup(DLSyms* pSyms) +{ + if(pSyms) { + munmap((void*) pSyms->pElf_Ehdr, pSyms->fileSize); + close(pSyms->file); + dlFreeMem(pSyms); + } +} + + +int dlSymsCount(DLSyms* pSyms) +{ + if (!pSyms) + return 0; + return pSyms->nSymbols; +} + + +const char* dlSymsName(DLSyms* pSyms, int index) +{ + int str_index; + if(!pSyms || !pSyms->pSymTab || index < 0 || index >= pSyms->nSymbols) + return NULL; + + str_index = pSyms->pSymTab[index].st_name; + if (str_index < 0 || str_index >= pSyms->strTabSize) + return NULL; + return &pSyms->pStrTab[str_index]; +} + + +const char* dlSymsNameFromValue(DLSyms* pSyms, void* value) +{ + Dl_info info; + return (dladdr(value, &info) && (value == info.dli_saddr)) + ? info.dli_sname + : NULL; +} +