Mercurial > pub > dyncall > dyncall
diff dynload/dynload_syms_mach-o.c @ 217:87c695673522
dynload darwin/mach-o update:
- removed unnecessarily complex darwin loader interface, and sharing with dynload_unix now
- mach-o symbol resolving refactored:
* to handle symlinks, relative paths, paths with random casing
* loading lib when not already loaded, for API consistency with ELF and PE implementations
author | Tassilo Philipp |
---|---|
date | Thu, 06 Apr 2017 12:00:36 +0200 |
parents | 3e629dc19168 |
children | 912efa3cfd4b |
line wrap: on
line diff
--- a/dynload/dynload_syms_mach-o.c Thu Apr 06 11:40:15 2017 +0200 +++ b/dynload/dynload_syms_mach-o.c Thu Apr 06 12:00:36 2017 +0200 @@ -6,7 +6,9 @@ Description: License: - Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com> + Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>, + 2017 refactored for stability, API consistency + and portability by Tassilo Philipp. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -32,76 +34,89 @@ #include "dynload.h" #include "dynload_alloc.h" +#include "../autovar/autovar_ARCH.h" #include <mach-o/dyld.h> #include <mach-o/nlist.h> +#include <sys/stat.h> #include <dlfcn.h> #include <string.h> -#if defined(ARCH_X64) //@@@ use dyncall_macros.h +#if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h #define MACH_HEADER_TYPE mach_header_64 -#define SEGMENT_COMMAND segment_command_64 #define NLIST_TYPE nlist_64 #else #define MACH_HEADER_TYPE mach_header -#define SEGMENT_COMMAND segment_command #define NLIST_TYPE nlist #endif -struct DLLib_ -{ - char* libPath; - void* handle; -}; - - struct DLSyms_ { - const char* pStringTable; + DLLib* pLib; + const char* pStringTable; const struct NLIST_TYPE* pSymbolTable; - uint32_t symbolCount; + uint32_t symbolCount; }; -DLSyms* dlSymsInit(const char* libPath) +DLSyms* dlSymsInit(const char* libPath) { - DLSyms* pSyms = NULL; + DLLib* pLib; + DLSyms* pSyms; uint32_t iImage, nImages; + struct stat st0; + + if(stat(libPath, &st0) == -1) + return NULL; + + pLib = dlLoadLibrary(libPath); + if(!pLib) + return NULL; + + // Loop over all dynamically linked images. for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++) { + struct stat st1; const char* name = _dyld_get_image_name(iImage); - if (name && !strcmp(name, libPath)) + + if(name && (stat(name, &st1) != -1)) { - const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); - const char* pBase = ((const char*)pHeader); - if (pHeader->filetype != MH_DYLIB) - return NULL; - if (pHeader->flags & MH_SPLIT_SEGS) - return NULL; - - if (pHeader) + // Don't rely on name comparison alone, as libPath might be relative, symlink, differently + // cased, etc., but compare inode number with the one of the mapped dyld image. + if (st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/) { - uint32_t iCmd, nCmds = pHeader->ncmds; - const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); - - for (iCmd = 0; iCmd < nCmds; iCmd++) + const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); + const char* pBase = ((const char*)pHeader); + if (pHeader->filetype != MH_DYLIB) + return NULL; + if (pHeader->flags & MH_SPLIT_SEGS) + return NULL; + + if (pHeader) { - if (cmd->cmd == LC_SYMTAB) + uint32_t iCmd, nCmds = pHeader->ncmds; + const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); + + for (iCmd = 0; iCmd < nCmds; iCmd++) { - const struct symtab_command* scmd = (const struct symtab_command*)cmd; - - pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) ); - pSyms->symbolCount = scmd->nsyms; - pSyms->pStringTable = pBase + scmd->stroff; - pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); - - return pSyms; + if (cmd->cmd == LC_SYMTAB) + { + const struct symtab_command* scmd = (const struct symtab_command*)cmd; + + pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) ); + pSyms->symbolCount = scmd->nsyms; + pSyms->pStringTable = pBase + scmd->stroff; + pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); + pSyms->pLib = pLib; + + return pSyms; + } + cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize); } - cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize); } + break; } - break; } } return NULL; @@ -110,17 +125,15 @@ void dlSymsCleanup(DLSyms* pSyms) { - if (!pSyms) - return; - - dlFreeMem(pSyms); + if(pSyms) { + dlFreeLibrary(pSyms->pLib); + dlFreeMem(pSyms); + } } int dlSymsCount(DLSyms* pSyms) { - if (!pSyms) - return 0; - return pSyms->symbolCount; + return pSyms ? pSyms->symbolCount : 0; } static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index) @@ -128,11 +141,11 @@ const struct NLIST_TYPE* nl; if (!pSyms) return NULL; - + nl = pSyms->pSymbolTable + index; if (nl->n_un.n_strx <= 1) return NULL; // would be empty string anyway - + //TODO skip more symbols based on nl->n_desc and nl->n_type ? return nl; } @@ -141,20 +154,7 @@ const char* dlSymsName(DLSyms* pSyms, int index) { const struct NLIST_TYPE* nl = get_nlist(pSyms, index); - if (!nl) - return NULL; - - return pSyms->pStringTable + nl->n_un.n_strx; -} - - -void* dlSymsValue(DLSyms* pSyms, int index) -{ - const struct NLIST_TYPE* nl = get_nlist(pSyms, index); - if (!nl) - return NULL; - - return (void*) (ptrdiff_t) (nl->n_value); + return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL; } @@ -163,6 +163,7 @@ Dl_info info; if (!dladdr(value, &info) || (value != info.dli_saddr)) return NULL; - + return info.dli_sname; } +