Mercurial > pub > dyncall > dyncall
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 |