annotate dynload/dynload_syms_mach-o.c @ 27:523c45dfa8fb

- refactored arm calling conventions' callvm code, so that the code that keeps the caller from overwriting the return value on some platforms also works on OpenBSD (before we casted the function pointer to have long long as return type, to hint the caller that there is one, but that triggers an intentional SIGABRT on OpenBSD for security reasons; now the decl reflects this, directly)
author cslag
date Tue, 15 Sep 2015 12:48:52 +0200
parents 3e629dc19168
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 }