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