comparison 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 (2017-04-06)
parents 3e629dc19168
children 912efa3cfd4b
comparison
equal deleted inserted replaced
216:28bf0b231bce 217:87c695673522
4 Library: dynload 4 Library: dynload
5 File: dynload/dynload_syms_mach-o.c 5 File: dynload/dynload_syms_mach-o.c
6 Description: 6 Description:
7 License: 7 License:
8 8
9 Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com> 9 Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>,
10 2017 refactored for stability, API consistency
11 and portability by Tassilo Philipp.
10 12
11 Permission to use, copy, modify, and distribute this software for any 13 Permission to use, copy, modify, and distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above 14 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies. 15 copyright notice and this permission notice appear in all copies.
14 16
30 32
31 */ 33 */
32 34
33 #include "dynload.h" 35 #include "dynload.h"
34 #include "dynload_alloc.h" 36 #include "dynload_alloc.h"
37 #include "../autovar/autovar_ARCH.h"
35 38
36 #include <mach-o/dyld.h> 39 #include <mach-o/dyld.h>
37 #include <mach-o/nlist.h> 40 #include <mach-o/nlist.h>
41 #include <sys/stat.h>
38 #include <dlfcn.h> 42 #include <dlfcn.h>
39 #include <string.h> 43 #include <string.h>
40 44
41 #if defined(ARCH_X64) //@@@ use dyncall_macros.h 45 #if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h
42 #define MACH_HEADER_TYPE mach_header_64 46 #define MACH_HEADER_TYPE mach_header_64
43 #define SEGMENT_COMMAND segment_command_64
44 #define NLIST_TYPE nlist_64 47 #define NLIST_TYPE nlist_64
45 #else 48 #else
46 #define MACH_HEADER_TYPE mach_header 49 #define MACH_HEADER_TYPE mach_header
47 #define SEGMENT_COMMAND segment_command
48 #define NLIST_TYPE nlist 50 #define NLIST_TYPE nlist
49 #endif 51 #endif
50 52
51 53
52 struct DLLib_ 54 struct DLSyms_
53 { 55 {
54 char* libPath; 56 DLLib* pLib;
55 void* handle; 57 const char* pStringTable;
58 const struct NLIST_TYPE* pSymbolTable;
59 uint32_t symbolCount;
56 }; 60 };
57 61
58 62
59 struct DLSyms_ 63 DLSyms* dlSymsInit(const char* libPath)
60 { 64 {
61 const char* pStringTable; 65 DLLib* pLib;
62 const struct NLIST_TYPE* pSymbolTable; 66 DLSyms* pSyms;
63 uint32_t symbolCount; 67 uint32_t iImage, nImages;
64 }; 68 struct stat st0;
65 69
70 if(stat(libPath, &st0) == -1)
71 return NULL;
66 72
67 DLSyms* dlSymsInit(const char* libPath) 73 pLib = dlLoadLibrary(libPath);
68 { 74 if(!pLib)
69 DLSyms* pSyms = NULL; 75 return NULL;
70 uint32_t iImage, nImages; 76
77 // Loop over all dynamically linked images.
71 for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++) 78 for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++)
72 { 79 {
80 struct stat st1;
73 const char* name = _dyld_get_image_name(iImage); 81 const char* name = _dyld_get_image_name(iImage);
74 if (name && !strcmp(name, libPath)) 82
83 if(name && (stat(name, &st1) != -1))
75 { 84 {
76 const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); 85 // Don't rely on name comparison alone, as libPath might be relative, symlink, differently
77 const char* pBase = ((const char*)pHeader); 86 // cased, etc., but compare inode number with the one of the mapped dyld image.
78 if (pHeader->filetype != MH_DYLIB) 87 if (st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/)
79 return NULL; 88 {
80 if (pHeader->flags & MH_SPLIT_SEGS) 89 const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage);
81 return NULL; 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;
82 95
83 if (pHeader) 96 if (pHeader)
84 {
85 uint32_t iCmd, nCmds = pHeader->ncmds;
86 const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
87
88 for (iCmd = 0; iCmd < nCmds; iCmd++)
89 { 97 {
90 if (cmd->cmd == LC_SYMTAB) 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++)
91 { 102 {
92 const struct symtab_command* scmd = (const struct symtab_command*)cmd; 103 if (cmd->cmd == LC_SYMTAB)
93 104 {
94 pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) ); 105 const struct symtab_command* scmd = (const struct symtab_command*)cmd;
95 pSyms->symbolCount = scmd->nsyms; 106
96 pSyms->pStringTable = pBase + scmd->stroff; 107 pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) );
97 pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); 108 pSyms->symbolCount = scmd->nsyms;
98 109 pSyms->pStringTable = pBase + scmd->stroff;
99 return pSyms; 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);
100 } 116 }
101 cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
102 } 117 }
118 break;
103 } 119 }
104 break;
105 } 120 }
106 } 121 }
107 return NULL; 122 return NULL;
108 } 123 }
109 124
110 125
111 void dlSymsCleanup(DLSyms* pSyms) 126 void dlSymsCleanup(DLSyms* pSyms)
112 { 127 {
113 if (!pSyms) 128 if(pSyms) {
114 return; 129 dlFreeLibrary(pSyms->pLib);
115 130 dlFreeMem(pSyms);
116 dlFreeMem(pSyms); 131 }
117 } 132 }
118 133
119 int dlSymsCount(DLSyms* pSyms) 134 int dlSymsCount(DLSyms* pSyms)
120 { 135 {
121 if (!pSyms) 136 return pSyms ? pSyms->symbolCount : 0;
122 return 0;
123 return pSyms->symbolCount;
124 } 137 }
125 138
126 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index) 139 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index)
127 { 140 {
128 const struct NLIST_TYPE* nl; 141 const struct NLIST_TYPE* nl;
129 if (!pSyms) 142 if (!pSyms)
130 return NULL; 143 return NULL;
131 144
132 nl = pSyms->pSymbolTable + index; 145 nl = pSyms->pSymbolTable + index;
133 if (nl->n_un.n_strx <= 1) 146 if (nl->n_un.n_strx <= 1)
134 return NULL; // would be empty string anyway 147 return NULL; // would be empty string anyway
135 148
136 //TODO skip more symbols based on nl->n_desc and nl->n_type ? 149 //TODO skip more symbols based on nl->n_desc and nl->n_type ?
137 return nl; 150 return nl;
138 } 151 }
139 152
140 153
141 const char* dlSymsName(DLSyms* pSyms, int index) 154 const char* dlSymsName(DLSyms* pSyms, int index)
142 { 155 {
143 const struct NLIST_TYPE* nl = get_nlist(pSyms, index); 156 const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
144 if (!nl) 157 return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL;
145 return NULL;
146
147 return pSyms->pStringTable + nl->n_un.n_strx;
148 }
149
150
151 void* dlSymsValue(DLSyms* pSyms, int index)
152 {
153 const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
154 if (!nl)
155 return NULL;
156
157 return (void*) (ptrdiff_t) (nl->n_value);
158 } 158 }
159 159
160 160
161 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value) 161 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value)
162 { 162 {
163 Dl_info info; 163 Dl_info info;
164 if (!dladdr(value, &info) || (value != info.dli_saddr)) 164 if (!dladdr(value, &info) || (value != info.dli_saddr))
165 return NULL; 165 return NULL;
166 166
167 return info.dli_sname; 167 return info.dli_sname;
168 } 168 }
169