Mercurial > pub > dyncall > dyncall
comparison dynload/dynload_syms_mach-o.c @ 219:912efa3cfd4b
- mach-o symbol iteration stability fixes
author | Tassilo Philipp |
---|---|
date | Tue, 11 Apr 2017 09:37:14 +0200 |
parents | 87c695673522 |
children | 94dc0bdd7dbe |
comparison
equal
deleted
inserted
replaced
218:cb56f077fd37 | 219:912efa3cfd4b |
---|---|
1 /* | 1 /* |
2 | 2 |
3 Package: dyncall | 3 Package: dyncall |
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 | 10 2017 refactored completely for stability, API |
11 and portability by Tassilo Philipp. | 11 consistency and portability by Tassilo Philipp. |
12 | 12 |
13 Permission to use, copy, modify, and distribute this software for any | 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 | 14 purpose with or without fee is hereby granted, provided that the above |
15 copyright notice and this permission notice appear in all copies. | 15 copyright notice and this permission notice appear in all copies. |
16 | 16 |
25 */ | 25 */ |
26 | 26 |
27 | 27 |
28 | 28 |
29 /* | 29 /* |
30 | 30 |
31 dynamic symbol resolver for Mach-O | 31 dynamic symbol resolver for Mach-O |
32 | 32 |
33 */ | 33 */ |
34 | 34 |
35 #include "dynload.h" | 35 #include "dynload.h" |
42 #include <dlfcn.h> | 42 #include <dlfcn.h> |
43 #include <string.h> | 43 #include <string.h> |
44 | 44 |
45 #if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h | 45 #if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h |
46 #define MACH_HEADER_TYPE mach_header_64 | 46 #define MACH_HEADER_TYPE mach_header_64 |
47 #define SEGMENT_COMMAND segment_command_64 | |
47 #define NLIST_TYPE nlist_64 | 48 #define NLIST_TYPE nlist_64 |
48 #else | 49 #else |
49 #define MACH_HEADER_TYPE mach_header | 50 #define MACH_HEADER_TYPE mach_header |
50 #define NLIST_TYPE nlist | 51 #define NLIST_TYPE nlist |
52 #define SEGMENT_COMMAND segment_command | |
51 #endif | 53 #endif |
52 | 54 |
53 | 55 |
54 struct DLSyms_ | 56 struct DLSyms_ |
55 { | 57 { |
62 | 64 |
63 DLSyms* dlSymsInit(const char* libPath) | 65 DLSyms* dlSymsInit(const char* libPath) |
64 { | 66 { |
65 DLLib* pLib; | 67 DLLib* pLib; |
66 DLSyms* pSyms; | 68 DLSyms* pSyms; |
67 uint32_t iImage, nImages; | 69 uint32_t i, n; |
68 struct stat st0; | 70 struct stat st0; |
71 const struct MACH_HEADER_TYPE* pHeader = NULL; | |
69 | 72 |
70 if(stat(libPath, &st0) == -1) | 73 if(stat(libPath, &st0) == -1) |
71 return NULL; | 74 return NULL; |
72 | 75 |
73 pLib = dlLoadLibrary(libPath); | 76 pLib = dlLoadLibrary(libPath); |
74 if(!pLib) | 77 if(!pLib) |
75 return NULL; | 78 return NULL; |
76 | 79 |
77 // Loop over all dynamically linked images. | 80 // Loop over all dynamically linked images to find ours. |
78 for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++) | 81 for(i = 0, n = _dyld_image_count(); i < n; ++i) |
79 { | 82 { |
80 struct stat st1; | 83 struct stat st1; |
81 const char* name = _dyld_get_image_name(iImage); | 84 const char* name = _dyld_get_image_name(i); |
82 | 85 |
83 if(name && (stat(name, &st1) != -1)) | 86 if(name && (stat(name, &st1) != -1)) |
84 { | 87 { |
85 // Don't rely on name comparison alone, as libPath might be relative, symlink, differently | 88 // 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. | 89 // 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)*/) | 90 if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/) |
88 { | 91 { |
89 const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); | 92 pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i); |
90 const char* pBase = ((const char*)pHeader); | 93 break; // found header |
91 if (pHeader->filetype != MH_DYLIB) | |
92 return NULL; | |
93 if (pHeader->flags & MH_SPLIT_SEGS) | |
94 return NULL; | |
95 | |
96 if (pHeader) | |
97 { | |
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++) | |
102 { | |
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); | |
116 } | |
117 } | |
118 break; | |
119 } | 94 } |
120 } | 95 } |
121 } | 96 } |
97 | |
98 if(pHeader && (pHeader->filetype == MH_DYLIB) && !(pHeader->flags & MH_SPLIT_SEGS)) | |
99 { | |
100 const char* pBase = (const char*)pHeader; | |
101 uintptr_t slide = 0; | |
102 const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); | |
103 | |
104 for(i = 0, n = pHeader->ncmds; i < n; ++i, cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize)) | |
105 { | |
106 if(cmd->cmd == LC_SEGMENT) | |
107 { | |
108 const struct SEGMENT_COMMAND* seg = (struct SEGMENT_COMMAND*)cmd; | |
109 if((seg->fileoff == 0) && (seg->filesize != 0)) // Count segment sizes to slide over...@@@? | |
110 slide = (uintptr_t)pHeader - seg->vmaddr; | |
111 if(strcmp(seg->segname, "__LINKEDIT") == 0) | |
112 pBase = (const char*)(seg->vmaddr - seg->fileoff + slide); // Adjust pBase depending on __LINKEDIT segment | |
113 } | |
114 else if(cmd->cmd == LC_SYMTAB) | |
115 { | |
116 const struct symtab_command* scmd = (const struct symtab_command*)cmd; | |
117 | |
118 // cmd->cmdsize must be size of struct, otherwise something is off; abort | |
119 if(cmd->cmdsize != sizeof(struct symtab_command)) | |
120 break; | |
121 | |
122 pSyms = (DLSyms*)dlAllocMem(sizeof(DLSyms)); | |
123 pSyms->symbolCount = scmd->nsyms; | |
124 pSyms->pStringTable = pBase + scmd->stroff; | |
125 pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); | |
126 pSyms->pLib = pLib; | |
127 | |
128 return pSyms; | |
129 } | |
130 //@@@ handle also LC_DYSYMTAB | |
131 } | |
132 } | |
133 | |
134 // Couldn't init syms, so free lib and return error. | |
135 dlFreeLibrary(pLib); | |
122 return NULL; | 136 return NULL; |
123 } | 137 } |
124 | 138 |
125 | 139 |
126 void dlSymsCleanup(DLSyms* pSyms) | 140 void dlSymsCleanup(DLSyms* pSyms) |
134 int dlSymsCount(DLSyms* pSyms) | 148 int dlSymsCount(DLSyms* pSyms) |
135 { | 149 { |
136 return pSyms ? pSyms->symbolCount : 0; | 150 return pSyms ? pSyms->symbolCount : 0; |
137 } | 151 } |
138 | 152 |
139 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index) | 153 |
154 const char* dlSymsName(DLSyms* pSyms, int index) | |
140 { | 155 { |
141 const struct NLIST_TYPE* nl; | 156 const struct NLIST_TYPE* nl; |
142 if (!pSyms) | 157 unsigned char t; |
158 | |
159 //@@@ mach-o ref: http://www.cilinder.be/docs/next/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/index.html | |
160 | |
161 if(!pSyms) | |
143 return NULL; | 162 return NULL; |
144 | 163 |
145 nl = pSyms->pSymbolTable + index; | 164 nl = pSyms->pSymbolTable + index; |
146 if (nl->n_un.n_strx <= 1) | 165 |
147 return NULL; // would be empty string anyway | 166 // Mach-O manual: Symbols with an index into the string table of zero |
167 // (n_un.n_strx == 0) are defined to have a null ("") name. | |
168 if(nl->n_un.n_strx == 0) | |
169 return NULL; //@@@ have return pointer to some static "" string? | |
170 | |
171 // Skip undefined symbols. @@@ should we? | |
172 t = nl->n_type & N_TYPE; | |
173 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 | |
174 return NULL; | |
148 | 175 |
149 //TODO skip more symbols based on nl->n_desc and nl->n_type ? | 176 //TODO skip more symbols based on nl->n_desc and nl->n_type ? |
150 return nl; | |
151 } | |
152 | 177 |
153 | 178 // Return name - handles lookup of indirect names. |
154 const char* dlSymsName(DLSyms* pSyms, int index) | 179 return &pSyms->pStringTable[t == N_INDR ? nl->n_value : nl->n_un.n_strx]; |
155 { | |
156 const struct NLIST_TYPE* nl = get_nlist(pSyms, index); | |
157 return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL; | |
158 } | 180 } |
159 | 181 |
160 | 182 |
161 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value) | 183 const char* dlSymsNameFromValue(DLSyms* pSyms, void* value) |
162 { | 184 { |