]> git.saurik.com Git - cycript.git/blob - Trampoline.t.cpp
Port and package (a Cydia release) for iOS 7 ARM64.
[cycript.git] / Trampoline.t.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <TargetConditionals.h>
23 #undef TARGET_IPHONE_SIMULATOR
24 #define TARGET_IPHONE_SIMULATOR 1
25 #define _PTHREAD_ATTR_T
26 #include <pthread_internals.h>
27 #undef TARGET_IPHONE_SIMULATOR
28 #define TARGET_IPHONE_SIMULATOR 0
29
30 #include <mach-o/dyld.h>
31 #include <mach-o/dyld_images.h>
32 #include <mach-o/loader.h>
33 #include <mach-o/nlist.h>
34
35 #include "Standard.hpp"
36 #include "Baton.hpp"
37
38 static void $bzero(void *data, size_t size) {
39 char *bytes(reinterpret_cast<char *>(data));
40 for (size_t i(0); i != size; ++i)
41 bytes[i] = 0;
42 }
43
44 static int $strcmp(const char *lhs, const char *rhs) {
45 while (*lhs == *rhs) {
46 if (*lhs == '\0')
47 return 0;
48 ++lhs, ++rhs;
49 } return *lhs < *rhs ? -1 : 1;
50 }
51
52 #ifdef __LP64__
53 typedef struct mach_header_64 mach_header_xx;
54 typedef struct nlist_64 nlist_xx;
55 typedef struct segment_command_64 segment_command_xx;
56
57 static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64;
58 static const uint32_t MH_MAGIC_XX = MH_MAGIC_64;
59 #else
60 typedef struct mach_header mach_header_xx;
61 typedef struct nlist nlist_xx;
62 typedef struct segment_command segment_command_xx;
63
64 static const uint32_t LC_SEGMENT_XX = LC_SEGMENT;
65 static const uint32_t MH_MAGIC_XX = MH_MAGIC;
66 #endif
67
68 #define forlc(command, mach, lc, type) \
69 if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
70 if (const struct load_command *lcp = load_commands) \
71 for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
72 if ( \
73 lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
74 reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
75 ) \
76 return NULL; \
77 else if (lcp->cmd != lc) \
78 continue; \
79 else if (lcp->cmdsize < sizeof(type)) \
80 return NULL; \
81 else if (const type *command = reinterpret_cast<const type *>(lcp))
82
83 static const mach_header_xx *Library(struct dyld_all_image_infos *infos, const char *name) {
84 for (uint32_t i(0); i != infos->infoArrayCount; ++i) {
85 const dyld_image_info &info(infos->infoArray[i]);
86 const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info.imageLoadAddress));
87 if (mach->magic != MH_MAGIC_XX)
88 continue;
89
90 const char *path(info.imageFilePath);
91 forlc (dylib, mach, LC_ID_DYLIB, dylib_command)
92 path = reinterpret_cast<const char *>(dylib) + dylib->dylib.name.offset;
93 if ($strcmp(path, name) != 0)
94 continue;
95
96 return mach;
97 }
98
99 return NULL;
100 }
101
102 static void *Symbol(const mach_header_xx *mach, const char *name) {
103 const struct symtab_command *stp(NULL);
104 forlc (command, mach, LC_SYMTAB, struct symtab_command)
105 stp = command;
106 if (stp == NULL)
107 return NULL;
108
109 size_t slide(_not(size_t));
110 const nlist_xx *symbols(NULL);
111 const char *strings(NULL);
112
113 forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) {
114 if (segment->fileoff == 0)
115 slide = reinterpret_cast<size_t>(mach) - segment->vmaddr;
116 if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize)
117 symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide);
118 if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize)
119 strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide);
120 }
121
122 if (slide == _not(size_t) || symbols == NULL || strings == NULL)
123 return NULL;
124
125 for (size_t i(0); i != stp->nsyms; ++i) {
126 const nlist_xx *symbol(&symbols[i]);
127 if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0)
128 continue;
129
130 const char *nambuf(strings + symbol->n_un.n_strx);
131 if ($strcmp(name, nambuf) != 0)
132 continue;
133
134 uintptr_t value(symbol->n_value);
135 if (value == 0)
136 continue;
137
138 #ifdef __arm__
139 if ((symbol->n_desc & N_ARM_THUMB_DEF) != 0)
140 value |= 0x00000001;
141 #endif
142
143 value += slide;
144 return reinterpret_cast<void *>(value);
145 }
146
147 return NULL;
148 }
149
150 template <typename Type_>
151 static _finline void cyset(Type_ &function, const char *name, const mach_header_xx *mach) {
152 function = reinterpret_cast<Type_>(Symbol(mach, name));
153 }
154
155 static _finline const mach_header_xx *Library(Baton *baton, const char *name) {
156 struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld));
157 return Library(infos, name);
158 }
159
160 void *Routine(void *arg) {
161 Baton *baton(reinterpret_cast<Baton *>(arg));
162
163 const mach_header_xx *dyld(NULL);
164 if (dyld == NULL)
165 dyld = Library(baton, "/usr/lib/system/libdyld.dylib");
166 if (dyld == NULL)
167 dyld = Library(baton, "/usr/lib/libSystem.B.dylib");
168
169 char *(*$dlerror)();
170 cyset($dlerror, "_dlerror", dyld);
171
172 void *(*$dlopen)(const char *, int);
173 cyset($dlopen, "_dlopen", dyld);
174
175 void *handle($dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
176 if (handle == NULL) {
177 $dlerror();
178 return NULL;
179 }
180
181 void *(*$dlsym)(void *, const char *);
182 cyset($dlsym, "_dlsym", dyld);
183
184 void (*CYHandleServer)(pid_t);
185 CYHandleServer = reinterpret_cast<void (*)(pid_t)>($dlsym(handle, "CYHandleServer"));
186 if (CYHandleServer == NULL) {
187 $dlerror();
188 return NULL;
189 }
190
191 CYHandleServer(baton->pid);
192 return NULL;
193 }
194
195 extern "C" void Start(Baton *baton) {
196 struct _pthread self;
197 $bzero(&self, sizeof(self));
198
199 const mach_header_xx *pthread(NULL);
200 if (pthread == NULL)
201 pthread = Library(baton, "/usr/lib/system/libsystem_pthread.dylib");
202 if (pthread == NULL)
203 pthread = Library(baton, "/usr/lib/system/libsystem_c.dylib");
204 if (pthread == NULL)
205 pthread = Library(baton, "/usr/lib/libSystem.B.dylib");
206
207 void (*$__pthread_set_self)(pthread_t);
208 cyset($__pthread_set_self, "___pthread_set_self", pthread);
209
210 self.tsd[0] = &self;
211 $__pthread_set_self(&self);
212
213 int (*$pthread_attr_init)(pthread_attr_t *);
214 cyset($pthread_attr_init, "_pthread_attr_init", pthread);
215
216 #if 0
217 pthread_attr_t attr;
218 $pthread_attr_init(&attr);
219
220 int (*$pthread_attr_setdetachstate)(pthread_attr_t *, int);
221 cyset($pthread_attr_setdetachstate, "_pthread_attr_setdetachstate", pthread);
222
223 $pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
224 #endif
225
226 int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
227 cyset($pthread_create, "_pthread_create", pthread);
228
229 pthread_t thread;
230 $pthread_create(&thread, NULL, &Routine, baton);
231
232 #if 0
233 int (*$pthread_attr_destroy)(pthread_attr_t *);
234 cyset($pthread_attr_destroy, "_pthread_attr_destroy", pthread);
235
236 $pthread_attr_destroy(&attr);
237 #endif
238
239 #if defined(__arm__) || defined(__arm64__)
240 uintptr_t tpid;
241 #if defined(__arm__)
242 __asm__ ("mrc p15, 0, %0, c13, c0, 3\n" : "=r" (tpid));
243 #elif defined(__arm64__)
244 __asm__ ("mrs %0, tpidrro_el0\n" : "=r" (tpid));
245 #else
246 #error XXX
247 #endif
248
249 void **tsd;
250 tsd = reinterpret_cast<void **>(tpid & ~3);
251 if (tsd != NULL)
252 tsd[0] = &self;
253 #endif
254
255 int (*$pthread_join)(pthread_t, void **);
256 cyset($pthread_join, "_pthread_join", pthread);
257
258 void *status;
259 $pthread_join(thread, &status);
260
261 const mach_header_xx *kernel(NULL);
262 if (kernel == NULL)
263 kernel = Library(baton, "/usr/lib/system/libsystem_kernel.dylib");
264 if (kernel == NULL)
265 kernel = Library(baton, "/usr/lib/libSystem.B.dylib");
266
267 mach_port_t (*$mach_thread_self)();
268 cyset($mach_thread_self, "_mach_thread_self", kernel);
269
270 kern_return_t (*$thread_terminate)(thread_act_t);
271 cyset($thread_terminate, "_thread_terminate", kernel);
272
273 $thread_terminate($mach_thread_self());
274 }