0
+ − 1 /*
+ − 2
+ − 3 Package: dyncall
+ − 4 Library: dynload
+ − 5 File: dynload/dynload_syms_mach-o.c
+ − 6 Description:
+ − 7 License:
+ − 8
217
+ − 9 Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>,
+ − 10 2017 refactored for stability, API consistency
+ − 11 and portability by Tassilo Philipp.
0
+ − 12
+ − 13 Permission to use, copy, modify, and distribute this software for any
+ − 14 purpose with or without fee is hereby granted, provided that the above
+ − 15 copyright notice and this permission notice appear in all copies.
+ − 16
+ − 17 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ − 18 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ − 19 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ − 20 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ − 21 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ − 22 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ − 23 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ − 24
+ − 25 */
+ − 26
+ − 27
+ − 28
+ − 29 /*
+ − 30
+ − 31 dynamic symbol resolver for Mach-O
+ − 32
+ − 33 */
+ − 34
+ − 35 #include "dynload.h"
+ − 36 #include "dynload_alloc.h"
217
+ − 37 #include "../autovar/autovar_ARCH.h"
0
+ − 38
+ − 39 #include <mach-o/dyld.h>
+ − 40 #include <mach-o/nlist.h>
217
+ − 41 #include <sys/stat.h>
0
+ − 42 #include <dlfcn.h>
+ − 43 #include <string.h>
+ − 44
217
+ − 45 #if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h
0
+ − 46 #define MACH_HEADER_TYPE mach_header_64
+ − 47 #define NLIST_TYPE nlist_64
+ − 48 #else
+ − 49 #define MACH_HEADER_TYPE mach_header
+ − 50 #define NLIST_TYPE nlist
+ − 51 #endif
+ − 52
+ − 53
+ − 54 struct DLSyms_
+ − 55 {
217
+ − 56 DLLib* pLib;
+ − 57 const char* pStringTable;
0
+ − 58 const struct NLIST_TYPE* pSymbolTable;
217
+ − 59 uint32_t symbolCount;
0
+ − 60 };
+ − 61
+ − 62
217
+ − 63 DLSyms* dlSymsInit(const char* libPath)
0
+ − 64 {
217
+ − 65 DLLib* pLib;
+ − 66 DLSyms* pSyms;
0
+ − 67 uint32_t iImage, nImages;
217
+ − 68 struct stat st0;
+ − 69
+ − 70 if(stat(libPath, &st0) == -1)
+ − 71 return NULL;
+ − 72
+ − 73 pLib = dlLoadLibrary(libPath);
+ − 74 if(!pLib)
+ − 75 return NULL;
+ − 76
+ − 77 // Loop over all dynamically linked images.
0
+ − 78 for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++)
+ − 79 {
217
+ − 80 struct stat st1;
0
+ − 81 const char* name = _dyld_get_image_name(iImage);
217
+ − 82
+ − 83 if(name && (stat(name, &st1) != -1))
0
+ − 84 {
217
+ − 85 // Don't rely on name comparison alone, as libPath might be relative, symlink, differently
+ − 86 // cased, etc., but compare inode number with the one of the mapped dyld image.
+ − 87 if (st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/)
0
+ − 88 {
217
+ − 89 const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage);
+ − 90 const char* pBase = ((const char*)pHeader);
+ − 91 if (pHeader->filetype != MH_DYLIB)
+ − 92 return NULL;
+ − 93 if (pHeader->flags & MH_SPLIT_SEGS)
+ − 94 return NULL;
+ − 95
+ − 96 if (pHeader)
0
+ − 97 {
217
+ − 98 uint32_t iCmd, nCmds = pHeader->ncmds;
+ − 99 const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
+ − 100
+ − 101 for (iCmd = 0; iCmd < nCmds; iCmd++)
0
+ − 102 {
217
+ − 103 if (cmd->cmd == LC_SYMTAB)
+ − 104 {
+ − 105 const struct symtab_command* scmd = (const struct symtab_command*)cmd;
+ − 106
+ − 107 pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) );
+ − 108 pSyms->symbolCount = scmd->nsyms;
+ − 109 pSyms->pStringTable = pBase + scmd->stroff;
+ − 110 pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff);
+ − 111 pSyms->pLib = pLib;
+ − 112
+ − 113 return pSyms;
+ − 114 }
+ − 115 cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
0
+ − 116 }
+ − 117 }
217
+ − 118 break;
0
+ − 119 }
+ − 120 }
+ − 121 }
+ − 122 return NULL;
+ − 123 }
+ − 124
+ − 125
+ − 126 void dlSymsCleanup(DLSyms* pSyms)
+ − 127 {
217
+ − 128 if(pSyms) {
+ − 129 dlFreeLibrary(pSyms->pLib);
+ − 130 dlFreeMem(pSyms);
+ − 131 }
0
+ − 132 }
+ − 133
+ − 134 int dlSymsCount(DLSyms* pSyms)
+ − 135 {
217
+ − 136 return pSyms ? pSyms->symbolCount : 0;
0
+ − 137 }
+ − 138
+ − 139 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index)
+ − 140 {
+ − 141 const struct NLIST_TYPE* nl;
+ − 142 if (!pSyms)
+ − 143 return NULL;
217
+ − 144
0
+ − 145 nl = pSyms->pSymbolTable + index;
+ − 146 if (nl->n_un.n_strx <= 1)
+ − 147 return NULL; // would be empty string anyway
217
+ − 148
0
+ − 149 //TODO skip more symbols based on nl->n_desc and nl->n_type ?
+ − 150 return nl;
+ − 151 }
+ − 152
+ − 153
+ − 154 const char* dlSymsName(DLSyms* pSyms, int index)
+ − 155 {
+ − 156 const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
217
+ − 157 return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL;
0
+ − 158 }
+ − 159
+ − 160
+ − 161 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value)
+ − 162 {
+ − 163 Dl_info info;
+ − 164 if (!dladdr(value, &info) || (value != info.dli_saddr))
+ − 165 return NULL;
217
+ − 166
0
+ − 167 return info.dli_sname;
+ − 168 }
217
+ − 169