annotate dynload/dynload_syms_mach-o.c @ 0:3e629dc19168

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:24:28 +0100
parents
children 87c695673522
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
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
9 Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
10
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
11 Permission to use, copy, modify, and distribute this software for any
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
12 purpose with or without fee is hereby granted, provided that the above
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
13 copyright notice and this permission notice appear in all copies.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
14
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
15 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
16 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
17 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
18 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
22
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
23 */
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 dynamic symbol resolver for Mach-O
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
30
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
31 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
32
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
33 #include "dynload.h"
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
34 #include "dynload_alloc.h"
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
35
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
36 #include <mach-o/dyld.h>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
37 #include <mach-o/nlist.h>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
38 #include <dlfcn.h>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
39 #include <string.h>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
40
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
41 #if defined(ARCH_X64) //@@@ use dyncall_macros.h
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
42 #define MACH_HEADER_TYPE mach_header_64
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
43 #define SEGMENT_COMMAND segment_command_64
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
44 #define NLIST_TYPE nlist_64
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
45 #else
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
46 #define MACH_HEADER_TYPE mach_header
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
47 #define SEGMENT_COMMAND segment_command
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
48 #define NLIST_TYPE nlist
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
49 #endif
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
50
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
51
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
52 struct DLLib_
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
53 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
54 char* libPath;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
55 void* handle;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
56 };
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
57
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
58
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
59 struct DLSyms_
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
60 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
61 const char* pStringTable;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
62 const struct NLIST_TYPE* pSymbolTable;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
63 uint32_t symbolCount;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
64 };
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
65
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
66
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
67 DLSyms* dlSymsInit(const char* libPath)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
68 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
69 DLSyms* pSyms = NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
70 uint32_t iImage, nImages;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
71 for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
72 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
73 const char* name = _dyld_get_image_name(iImage);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
74 if (name && !strcmp(name, libPath))
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
75 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
76 const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
77 const char* pBase = ((const char*)pHeader);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
78 if (pHeader->filetype != MH_DYLIB)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
79 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
80 if (pHeader->flags & MH_SPLIT_SEGS)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
81 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
82
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
83 if (pHeader)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
84 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
85 uint32_t iCmd, nCmds = pHeader->ncmds;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
86 const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
87
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
88 for (iCmd = 0; iCmd < nCmds; iCmd++)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
89 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
90 if (cmd->cmd == LC_SYMTAB)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
91 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
92 const struct symtab_command* scmd = (const struct symtab_command*)cmd;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
93
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
94 pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) );
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
95 pSyms->symbolCount = scmd->nsyms;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
96 pSyms->pStringTable = pBase + scmd->stroff;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
97 pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
98
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
99 return pSyms;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
100 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
101 cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
102 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
103 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
104 break;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
105 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
106 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
107 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
108 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
109
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
110
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
111 void dlSymsCleanup(DLSyms* pSyms)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
112 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
113 if (!pSyms)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
114 return;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
115
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
116 dlFreeMem(pSyms);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
117 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
118
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
119 int dlSymsCount(DLSyms* pSyms)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
120 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
121 if (!pSyms)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
122 return 0;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
123 return pSyms->symbolCount;
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 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
127 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
128 const struct NLIST_TYPE* nl;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
129 if (!pSyms)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
130 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
131
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
132 nl = pSyms->pSymbolTable + index;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
133 if (nl->n_un.n_strx <= 1)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
134 return NULL; // would be empty string anyway
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
135
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
136 //TODO skip more symbols based on nl->n_desc and nl->n_type ?
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
137 return nl;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
138 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
139
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 char* dlSymsName(DLSyms* pSyms, int index)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
142 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
143 const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
144 if (!nl)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
145 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
146
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
147 return pSyms->pStringTable + nl->n_un.n_strx;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
148 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
149
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
150
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
151 void* dlSymsValue(DLSyms* pSyms, int index)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
152 {
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
153 const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
154 if (!nl)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
155 return NULL;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
156
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
157 return (void*) (ptrdiff_t) (nl->n_value);
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;
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
166
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 }