1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2014 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <TargetConditionals.h>
23 #if defined(__arm__) || defined(__arm64__)
24 #undef TARGET_IPHONE_SIMULATOR
25 #define TARGET_IPHONE_SIMULATOR 1
27 #define _PTHREAD_ATTR_T
28 #include <pthread_internals.h>
29 #if defined(__arm__) || defined(__arm64__)
30 #undef TARGET_IPHONE_SIMULATOR
33 #include <mach-o/dyld.h>
34 #include <mach-o/dyld_images.h>
35 #include <mach-o/loader.h>
36 #include <mach-o/nlist.h>
38 #include "Standard.hpp"
41 static void $
bzero(void *data
, size_t size
) {
42 char *bytes(reinterpret_cast<char *>(data
));
43 for (size_t i(0); i
!= size
; ++i
)
47 __attribute__((__unused__
))
48 static void $
memcpy(char *dst
, const char *src
, size_t size
) {
49 for (size_t i(0); i
!= size
; ++i
)
53 static int $
strcmp(const char *lhs
, const char *rhs
) {
54 while (*lhs
== *rhs
) {
58 } return *lhs
< *rhs
? -1 : 1;
61 static void $
strlcpy(char *dst
, const char *src
, size_t size
) {
67 while (i
!= size
- 1) {
75 __attribute__((__unused__
))
76 static char *$
strstr(const char *haystack
, const char *needle
) {
79 for (; *haystack
!= '\0'; ++haystack
)
80 for (size_t i(0); ; ++i
)
81 if (needle
[i
] == '\0')
82 return const_cast<char *>(haystack
);
83 else if (needle
[i
] != haystack
[i
])
88 __attribute__((__unused__
))
89 static size_t $
strlen(const char *data
) {
90 for (size_t i(0); ; ++i
)
95 __attribute__((__unused__
))
96 static void $
snprintfp(char *dst
, size_t size
, const void *pointer
) {
97 uintptr_t value(reinterpret_cast<uintptr_t>(pointer
));
99 char *end(buffer
+ sizeof(buffer
));
104 unsigned digit(value
& 0xf);
106 *--end
= (digit
< 10 ? '0' : 'a' - 10) + digit
;
107 } while (value
!= 0);
110 $
strlcpy(dst
, end
, size
);
114 typedef struct mach_header_64 mach_header_xx
;
115 typedef struct nlist_64 nlist_xx
;
116 typedef struct segment_command_64 segment_command_xx
;
118 static const uint32_t LC_SEGMENT_XX
= LC_SEGMENT_64
;
119 static const uint32_t MH_MAGIC_XX
= MH_MAGIC_64
;
121 typedef struct mach_header mach_header_xx
;
122 typedef struct nlist nlist_xx
;
123 typedef struct segment_command segment_command_xx
;
125 static const uint32_t LC_SEGMENT_XX
= LC_SEGMENT
;
126 static const uint32_t MH_MAGIC_XX
= MH_MAGIC
;
129 #define forlc(command, mach, lc, type) \
130 if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
131 if (const struct load_command *lcp = load_commands) \
132 for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
134 lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
135 reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
138 else if (lcp->cmd != lc) \
140 else if (lcp->cmdsize < sizeof(type)) \
142 else if (const type *command = reinterpret_cast<const type *>(lcp))
144 static const mach_header_xx
*Library(struct dyld_all_image_infos
*infos
, const char *name
) {
145 for (uint32_t i(0); i
!= infos
->infoArrayCount
; ++i
) {
146 const dyld_image_info
&info(infos
->infoArray
[i
]);
147 const mach_header_xx
*mach(reinterpret_cast<const mach_header_xx
*>(info
.imageLoadAddress
));
148 if (mach
->magic
!= MH_MAGIC_XX
)
151 const char *path(info
.imageFilePath
);
152 forlc (dylib
, mach
, LC_ID_DYLIB
, dylib_command
)
153 path
= reinterpret_cast<const char *>(dylib
) + dylib
->dylib
.name
.offset
;
154 if ($
strcmp(path
, name
) != 0)
163 static void *Symbol(const mach_header_xx
*mach
, const char *name
) {
164 const struct symtab_command
*stp(NULL
);
165 forlc (command
, mach
, LC_SYMTAB
, struct symtab_command
)
170 size_t slide(_not(size_t));
171 const nlist_xx
*symbols(NULL
);
172 const char *strings(NULL
);
174 forlc (segment
, mach
, LC_SEGMENT_XX
, segment_command_xx
) {
175 if (segment
->fileoff
== 0)
176 slide
= reinterpret_cast<size_t>(mach
) - segment
->vmaddr
;
177 if (stp
->symoff
>= segment
->fileoff
&& stp
->symoff
< segment
->fileoff
+ segment
->filesize
)
178 symbols
= reinterpret_cast<const nlist_xx
*>(stp
->symoff
- segment
->fileoff
+ segment
->vmaddr
+ slide
);
179 if (stp
->stroff
>= segment
->fileoff
&& stp
->stroff
< segment
->fileoff
+ segment
->filesize
)
180 strings
= reinterpret_cast<const char *>(stp
->stroff
- segment
->fileoff
+ segment
->vmaddr
+ slide
);
183 if (slide
== _not(size_t) || symbols
== NULL
|| strings
== NULL
)
186 for (size_t i(0); i
!= stp
->nsyms
; ++i
) {
187 const nlist_xx
*symbol(&symbols
[i
]);
188 if (symbol
->n_un
.n_strx
== 0 || (symbol
->n_type
& N_STAB
) != 0)
191 const char *nambuf(strings
+ symbol
->n_un
.n_strx
);
192 if ($
strcmp(name
, nambuf
) != 0)
195 uintptr_t value(symbol
->n_value
);
200 if ((symbol
->n_desc
& N_ARM_THUMB_DEF
) != 0)
205 return reinterpret_cast<void *>(value
);
211 template <typename Type_
>
212 static _finline
void cyset(Type_
&function
, const char *name
, const mach_header_xx
*mach
) {
213 function
= reinterpret_cast<Type_
>(Symbol(mach
, name
));
216 static _finline
const mach_header_xx
*Library(Baton
*baton
, const char *name
) {
217 struct dyld_all_image_infos
*infos(reinterpret_cast<struct dyld_all_image_infos
*>(baton
->dyld
));
218 return Library(infos
, name
);
221 #if defined(__i386__) || defined(__x86_64__)
222 static bool Simulator(struct dyld_all_image_infos
*infos
) {
223 for (uint32_t i(0); i
!= infos
->infoArrayCount
; ++i
) {
224 const dyld_image_info
&info(infos
->infoArray
[i
]);
225 const char *path(info
.imageFilePath
);
226 if ($
strstr(path
, "/SDKs/iPhoneSimulator") != NULL
)
231 static bool Simulator(Baton
*baton
) {
232 struct dyld_all_image_infos
*infos(reinterpret_cast<struct dyld_all_image_infos
*>(baton
->dyld
));
233 return Simulator(infos
);
237 void *Routine(void *arg
) {
238 Baton
*baton(reinterpret_cast<Baton
*>(arg
));
240 const mach_header_xx
*dyld(NULL
);
242 dyld
= Library(baton
, "/usr/lib/system/libdyld.dylib");
244 dyld
= Library(baton
, "/usr/lib/libSystem.B.dylib");
247 cyset($dlerror
, "_dlerror", dyld
);
249 void *(*$dlopen
)(const char *, int);
250 cyset($dlopen
, "_dlopen", dyld
);
252 #if defined(__i386__) || defined(__x86_64__)
253 size_t length($
strlen(baton
->library
));
254 if (length
>= 10 && $
strcmp(baton
->library
+ length
- 10, "-###.dylib") == 0)
255 $
memcpy(baton
->library
+ length
- 10, Simulator(baton
) ? "-sim" : "-sys", 4);
258 void *handle($
dlopen(baton
->library
, RTLD_LAZY
| RTLD_LOCAL
));
259 if (handle
== NULL
) {
260 $
strlcpy(baton
->error
, $
dlerror(), sizeof(baton
->error
));
264 void *(*$dlsym
)(void *, const char *);
265 cyset($dlsym
, "_dlsym", dyld
);
267 void (*CYHandleServer
)(pid_t
);
268 CYHandleServer
= reinterpret_cast<void (*)(pid_t
)>($
dlsym(handle
, "CYHandleServer"));
269 if (CYHandleServer
== NULL
) {
270 $
strlcpy(baton
->error
, $
dlerror(), sizeof(baton
->error
));
274 CYHandleServer(baton
->pid
);
278 extern "C" void Start(Baton
*baton
) {
279 struct _pthread self
;
280 $
bzero(&self
, sizeof(self
));
282 const mach_header_xx
*pthread(NULL
);
284 pthread
= Library(baton
, "/usr/lib/system/libsystem_pthread.dylib");
286 pthread
= Library(baton
, "/usr/lib/system/libsystem_c.dylib");
288 pthread
= Library(baton
, "/usr/lib/libSystem.B.dylib");
290 void (*$__pthread_set_self
)(void **);
291 cyset($__pthread_set_self
, "___pthread_set_self", pthread
);
294 $
__pthread_set_self(&self
.tsd
[0]);
296 int (*$pthread_attr_init
)(pthread_attr_t
*);
297 cyset($pthread_attr_init
, "_pthread_attr_init", pthread
);
301 $
pthread_attr_init(&attr
);
303 int (*$pthread_attr_setdetachstate
)(pthread_attr_t
*, int);
304 cyset($pthread_attr_setdetachstate
, "_pthread_attr_setdetachstate", pthread
);
306 $
pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
309 int (*$pthread_create
)(pthread_t
*, const pthread_attr_t
*, void *(*)(void *), void *);
310 cyset($pthread_create
, "_pthread_create", pthread
);
313 $
pthread_create(&thread
, NULL
, &Routine
, baton
);
316 int (*$pthread_attr_destroy
)(pthread_attr_t
*);
317 cyset($pthread_attr_destroy
, "_pthread_attr_destroy", pthread
);
319 $
pthread_attr_destroy(&attr
);
322 int (*$pthread_join
)(pthread_t
, void **);
323 cyset($pthread_join
, "_pthread_join", pthread
);
326 $
pthread_join(thread
, &status
);
328 const mach_header_xx
*kernel(NULL
);
330 kernel
= Library(baton
, "/usr/lib/system/libsystem_kernel.dylib");
332 kernel
= Library(baton
, "/usr/lib/libSystem.B.dylib");
334 mach_port_t (*$mach_thread_self
)();
335 cyset($mach_thread_self
, "_mach_thread_self", kernel
);
337 kern_return_t (*$thread_terminate
)(thread_act_t
);
338 cyset($thread_terminate
, "_thread_terminate", kernel
);
340 $
thread_terminate($
mach_thread_self());