Mercurial > pub > dyncall > dyncall
annotate dynload/dynload_syms_mach-o.c @ 220:94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
- use C comments
author | Tassilo Philipp |
---|---|
date | Tue, 11 Apr 2017 15:13:32 +0200 |
parents | 912efa3cfd4b |
children | 7076f551faf5 |
rev | line source |
---|---|
0 | 1 /* |
2 | |
3 Package: dyncall | |
4 Library: dynload | |
5 File: dynload/dynload_syms_mach-o.c | |
219 | 6 Description: |
0 | 7 License: |
8 | |
217 | 9 Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>, |
219 | 10 2017 refactored completely for stability, API |
11 consistency 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 /* | |
219 | 30 |
0 | 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" |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
38 #include "../autovar/autovar_OS.h" |
0 | 39 |
40 #include <mach-o/dyld.h> | |
41 #include <mach-o/nlist.h> | |
217 | 42 #include <sys/stat.h> |
0 | 43 #include <dlfcn.h> |
44 #include <string.h> | |
45 | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
46 #if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) /*@@@ use dyncall_macros.h*/ |
0 | 47 #define MACH_HEADER_TYPE mach_header_64 |
219 | 48 #define SEGMENT_COMMAND segment_command_64 |
0 | 49 #define NLIST_TYPE nlist_64 |
50 #else | |
51 #define MACH_HEADER_TYPE mach_header | |
52 #define NLIST_TYPE nlist | |
219 | 53 #define SEGMENT_COMMAND segment_command |
0 | 54 #endif |
55 | |
56 | |
57 struct DLSyms_ | |
58 { | |
217 | 59 DLLib* pLib; |
60 const char* pStringTable; | |
0 | 61 const struct NLIST_TYPE* pSymbolTable; |
217 | 62 uint32_t symbolCount; |
0 | 63 }; |
64 | |
65 | |
217 | 66 DLSyms* dlSymsInit(const char* libPath) |
0 | 67 { |
217 | 68 DLLib* pLib; |
69 DLSyms* pSyms; | |
219 | 70 uint32_t i, n; |
217 | 71 struct stat st0; |
219 | 72 const struct MACH_HEADER_TYPE* pHeader = NULL; |
217 | 73 |
74 if(stat(libPath, &st0) == -1) | |
75 return NULL; | |
76 | |
77 pLib = dlLoadLibrary(libPath); | |
78 if(!pLib) | |
79 return NULL; | |
80 | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
81 /* Loop over all dynamically linked images to find ours. */ |
219 | 82 for(i = 0, n = _dyld_image_count(); i < n; ++i) |
0 | 83 { |
217 | 84 struct stat st1; |
219 | 85 const char* name = _dyld_get_image_name(i); |
217 | 86 |
87 if(name && (stat(name, &st1) != -1)) | |
0 | 88 { |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
89 /* Don't rely on name comparison alone, as libPath might be relative, symlink, differently */ |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
90 /* cased, etc., but compare inode number with the one of the mapped dyld image. */ |
219 | 91 if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/) |
0 | 92 { |
219 | 93 pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i); |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
94 break; /* found header */ |
0 | 95 } |
96 } | |
97 } | |
219 | 98 |
99 if(pHeader && (pHeader->filetype == MH_DYLIB) && !(pHeader->flags & MH_SPLIT_SEGS)) | |
100 { | |
101 const char* pBase = (const char*)pHeader; | |
102 uintptr_t slide = 0; | |
103 const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); | |
104 | |
105 for(i = 0, n = pHeader->ncmds; i < n; ++i, cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize)) | |
106 { | |
107 if(cmd->cmd == LC_SEGMENT) | |
108 { | |
109 const struct SEGMENT_COMMAND* seg = (struct SEGMENT_COMMAND*)cmd; | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
110 if((seg->fileoff == 0) && (seg->filesize != 0)) /* Count segment sizes to slide over...@@@? */ |
219 | 111 slide = (uintptr_t)pHeader - seg->vmaddr; |
112 if(strcmp(seg->segname, "__LINKEDIT") == 0) | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
113 pBase = (const char*)(seg->vmaddr - seg->fileoff + slide); /* Adjust pBase depending on __LINKEDIT segment */ |
219 | 114 } |
115 else if(cmd->cmd == LC_SYMTAB) | |
116 { | |
117 const struct symtab_command* scmd = (const struct symtab_command*)cmd; | |
118 | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
119 /* cmd->cmdsize must be size of struct, otherwise something is off; abort */ |
219 | 120 if(cmd->cmdsize != sizeof(struct symtab_command)) |
121 break; | |
122 | |
123 pSyms = (DLSyms*)dlAllocMem(sizeof(DLSyms)); | |
124 pSyms->symbolCount = scmd->nsyms; | |
125 pSyms->pStringTable = pBase + scmd->stroff; | |
126 pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); | |
127 pSyms->pLib = pLib; | |
128 | |
129 return pSyms; | |
130 } | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
131 /*@@@ handle also LC_DYSYMTAB */ |
219 | 132 } |
133 } | |
134 | |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
135 /* Couldn't init syms, so free lib and return error. */ |
219 | 136 dlFreeLibrary(pLib); |
0 | 137 return NULL; |
138 } | |
139 | |
140 | |
141 void dlSymsCleanup(DLSyms* pSyms) | |
142 { | |
217 | 143 if(pSyms) { |
144 dlFreeLibrary(pSyms->pLib); | |
145 dlFreeMem(pSyms); | |
146 } | |
0 | 147 } |
148 | |
149 int dlSymsCount(DLSyms* pSyms) | |
150 { | |
217 | 151 return pSyms ? pSyms->symbolCount : 0; |
0 | 152 } |
153 | |
219 | 154 |
155 const char* dlSymsName(DLSyms* pSyms, int index) | |
0 | 156 { |
157 const struct NLIST_TYPE* nl; | |
219 | 158 unsigned char t; |
159 | |
160 if(!pSyms) | |
0 | 161 return NULL; |
217 | 162 |
0 | 163 nl = pSyms->pSymbolTable + index; |
219 | 164 |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
165 /* Mach-O manual: Symbols with an index into the string table of zero */ |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
166 /* (n_un.n_strx == 0) are defined to have a null ("") name. */ |
219 | 167 if(nl->n_un.n_strx == 0) |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
168 return NULL; /*@@@ have return pointer to some static "" string? */ |
219 | 169 |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
170 /* Skip undefined symbols. @@@ should we? */ |
219 | 171 t = nl->n_type & N_TYPE; |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
172 if(t == N_UNDF || t == N_PBUD) /* @@@ check if N_PBUD is defined, it's not in the NeXT manual, but on Darwin 8.0.1 */ |
219 | 173 return NULL; |
217 | 174 |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
175 /*TODO skip more symbols based on nl->n_desc and nl->n_type ? */ |
0 | 176 |
220
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
177 /* Return name - handles lookup of indirect names. */ |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
178 return &pSyms->pStringTable[(t == N_INDR ? nl->n_value : nl->n_un.n_strx) |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
179 #if defined(OS_Darwin) |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
180 + 1 /* Skip '_'-prefix */ |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
181 #endif |
94dc0bdd7dbe
- make dynload symbol iteration return symbol names as in C code, on Darwin
Tassilo Philipp
parents:
219
diff
changeset
|
182 ]; |
0 | 183 } |
184 | |
185 | |
186 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value) | |
187 { | |
188 Dl_info info; | |
189 if (!dladdr(value, &info) || (value != info.dli_saddr)) | |
190 return NULL; | |
217 | 191 |
0 | 192 return info.dli_sname; |
193 } | |
217 | 194 |