#include <sys/types.h>
struct Baton {
- void (*_pthread_set_self)(pthread_t);
+ void (*__pthread_set_self)(pthread_t);
int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
int (*pthread_join)(pthread_t, void **);
library += -liconv
flags += -I/usr/include/ffi
apr_config := /usr/bin/apr-1-config
-
-ifeq ($(uname_p),i386)
-flags += -m32
-endif
+flags += -arch i386 -arch x86_64 #-arch armv6
flags += -DCY_ATTACH
code += Handler.o
inject += Mach/Inject.o
Mach/Inject.o: Trampoline.t.hpp Baton.hpp
-%.t.hpp: %.t.cpp
- $(target)gcc -c -fno-stack-protector -fno-exceptions -Iinclude -o $*.t.o $< $(flags) && { file=($$($(target)otool -l $*.t.o | sed -e 'x; /^1/ { x; /^ *filesize / { s/^.* //; p; }; /^ *fileoff / { s/^.* //; p; }; x; }; x; /^ *cmd LC_SEGMENT$$/ { s/.*/1/; x; }; d;')); od -t x1 -j $${file[0]} -N $${file[1]} $*.t.o | sed -e 's/^[^ ]*//' | tr $$'\n' ' ' | sed -e 's/ */ /g;s/^ *//;s/ $$//;s/ /,/g;s/\([^,][^,]\)/0x\1/g' | sed -e 's/^/static const char $*_[] = {/;s/$$/};/' && echo && echo "/*" && $(target)otool -vVt $*.t.o && echo "*/"; } >$@ && rm -f $*.t.o
+%.t.hpp: %.t.cpp trampoline.sh Baton.hpp Trampoline.hpp Darwin.mk
+ ./trampoline.sh $@ $*.t.dylib $* sed $(target){otool,lipo,nm,gcc} $(flags) -dynamiclib -g0 -fno-stack-protector -fno-exceptions -Iinclude $< -o $*.t.dylib
clean::
rm -f Trampoline.t.hpp
Mach/Inject.lo: Trampoline.t.hpp Baton.hpp
-%.t.hpp: %.t.cpp
- # LC_SEGMENT_64
- $(libtool) --mode=compile $(cxx) -c -fno-stack-protector -fno-exceptions -I$(srcdir)/include -o $*.t.lo $< $(cflags) && { file=($$($(otool) -l .libs/$*.t.o | $(sed) -e 'x; /^1/ { x; /^ *filesize / { s/^.* //; p; }; /^ *fileoff / { s/^.* //; p; }; x; }; x; /^ *cmd LC_SEGMENT/ { s/.*/1/; x; }; d;')); od -t x1 -j $${file[0]} -N $${file[1]} .libs/$*.t.o | $(sed) -e 's/^[^ ]*//' | tr $$'\n' ' ' | $(sed) -e 's/ */ /g;s/^ *//;s/ $$//;s/ /,/g;s/\([^,][^,]\)/0x\1/g' | $(sed) -e 's/^/static const char $*_[] = {/;s/$$/};/' && echo && echo "/*" && $(otool) -vVt .libs/$*.t.o && echo "*/"; } >$@ && rm -f $*.t.lo .libs/$*.t.o
+%.t.hpp: %.t.cpp trampoline.sh Baton.hpp Trampoline.hpp
+ # DOUG: abstract "lipo" and "nm" with configure?
+ ./trampoline.sh $@ .libs/lib$*.t.dylib $* $(sed) $(otool) lipo nm $(libtool) --mode=compile $(cxx) -dynamiclib -fno-stack-protector -fno-exceptions -I$(srcdir)/include -o lib$*.t.la $< $(cflags)
endif
endif
#include <dlfcn.h>
#include <mach/mach.h>
-extern "C" {
-#include <mach-o/nlist.h>
-}
+#include <mach/i386/thread_status.h>
#include <cstdio>
#include <pthread.h>
extern "C" void __pthread_set_self(pthread_t);
-template <typename Type_>
-static void nlset(Type_ &function, struct nlist *nl, size_t index) {
- struct nlist &name(nl[index]);
- uintptr_t value(name.n_value);
- _assert(value != 0);
- if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
- value |= 0x00000001;
- function = value;
-}
-
void InjectLibrary(pid_t pid) {
- // XXX: break this into the build environment
+ // DOUG: turn this into some kind of -D passed from configure
const char *library("/usr/lib/libcycript.dylib");
static const size_t Stack_(8 * 1024);
uint8_t *local(reinterpret_cast<uint8_t *>(apr_palloc(pool, depth)));
Baton *baton(reinterpret_cast<Baton *>(local));
- uintptr_t set_self_internal;
- uintptr_t set_self_external;
-
-#if defined(__i386__) || defined(__arm__)
- struct nlist nl[3];
- memset(nl, 0, sizeof(nl));
- nl[0].n_un.n_name = (char *) "__pthread_set_self";
- nl[1].n_un.n_name = (char *) "___pthread_set_self";
- nlist("/usr/lib/libSystem.B.dylib", nl);
- nlset(set_self_internal, nl, 0);
- nlset(set_self_external, nl, 1);
-#else
- set_self_internal = 0;
- set_self_external = 0;
-#endif
-
- baton->_pthread_set_self = reinterpret_cast<void (*)(pthread_t)>(reinterpret_cast<uintptr_t>(&__pthread_set_self) - set_self_external + set_self_internal);
+ baton->__pthread_set_self = &__pthread_set_self;
baton->pthread_create = &pthread_create;
baton->pthread_join = &pthread_join;
vm_write(task, data, reinterpret_cast<vm_address_t>(baton), depth);
- vm_address_t code;
- _krncall(vm_allocate(task, &code, sizeof(Trampoline_), true));
- vm_write(task, code, reinterpret_cast<vm_address_t>(Trampoline_), sizeof(Trampoline_));
- _krncall(vm_protect(task, code, sizeof(Trampoline_), false, VM_PROT_READ | VM_PROT_EXECUTE));
-
thread_act_t thread;
_krncall(thread_create(task, &thread));
mach_msg_type_number_t count;
size_t push;
+ Trampoline *trampoline;
+
#if defined(__arm__)
+ trampoline = &Trampoline_arm_;
arm_thread_state_t state;
flavor = ARM_THREAD_STATE;
count = ARM_THREAD_STATE_COUNT;
push = 0;
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
+ trampoline = &Trampoline_i386_;
i386_thread_state_t state;
flavor = i386_THREAD_STATE;
count = i386_THREAD_STATE_COUNT;
push = 5;
+#elif defined(__x86_64__)
+ trampoline = &Trampoline_x86_64_;
+ x86_thread_state64_t state;
+ flavor = x86_THREAD_STATE64;
+ count = x86_THREAD_STATE64_COUNT;
+ push = 2;
#else
#error XXX: implement
#endif
- uintptr_t frame[push];
+ vm_address_t code;
+ _krncall(vm_allocate(task, &code, trampoline->size_, true));
+ vm_write(task, code, reinterpret_cast<vm_address_t>(trampoline->data_), trampoline->size_);
+ _krncall(vm_protect(task, code, trampoline->size_, false, VM_PROT_READ | VM_PROT_EXECUTE));
+
+ printf("_ptss:%p\n", baton->__pthread_set_self);
+ printf("dlsym:%p\n", baton->dlsym);
+ printf("code:%zx\n", (size_t) code);
+
+ uint32_t frame[push];
if (sizeof(frame) != 0)
memset(frame, 0, sizeof(frame));
-
memset(&state, 0, sizeof(state));
mach_msg_type_number_t read(count);
#if defined(__arm__)
state.r[0] = data;
state.sp = stack + Stack_;
- state.pc = code;
+ state.pc = code + trampoline->entry_;
if ((state.pc & 0x1) != 0) {
state.pc &= ~0x1;
state.cpsr |= 0x20;
}
-#elif defined(__i386__) || defined(__x86_64__)
- frame[0] = 0;
+#elif defined(__i386__)
frame[1] = data;
- state.__eip = code;
+ state.__eip = code + trampoline->entry_;
state.__esp = stack + Stack_ - sizeof(frame);
+#elif defined(__x86_64__)
+ frame[0] = 0xdeadbeef;
+ state.__rdi = data;
+ state.__rip = code + trampoline->entry_;
+ state.__rsp = stack + Stack_ - sizeof(frame);
#else
#error XXX: implement
#endif
--- /dev/null
+/* Cycript - Inlining/Optimizing JavaScript Compiler
+ * Copyright (C) 2010 Jay Freeman (saurik)
+*/
+
+/* Modified BSD License {{{ */
+/*
+ * Redistribution and use in source and binary
+ * forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the
+ * above copyright notice, this list of conditions
+ * and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation
+ * and/or other materials provided with the
+ * distribution.
+ * 3. The name of the author may not be used to endorse
+ * or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* }}} */
+
+struct Trampoline {
+ const char *data_;
+ size_t size_;
+ size_t entry_;
+};
#define _PTHREAD_ATTR_T
#include <pthread_internals.h>
+#include "Standard.hpp"
#include "Baton.hpp"
-void *Routine(void *);
+template <typename Type_>
+static _finline void dlset(Baton *baton, Type_ &function, const char *name, void *handle = RTLD_DEFAULT) {
+ function = reinterpret_cast<Type_>(baton->dlsym(handle, name));
+}
+
+void *Routine(void *arg) {
+ Baton *baton(reinterpret_cast<Baton *>(arg));
+
+ void *(*dlopen)(const char *, int);
+ dlset(baton, dlopen, "dlopen");
+
+ void *handle(dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
+
+ void (*CYHandleServer)(pid_t);
+ dlset(baton, CYHandleServer, "CYHandleServer", handle);
+
+ CYHandleServer(baton->pid);
+
+ return arg;
+}
+
+static void $bzero(void *data, size_t size) {
+ char *bytes(reinterpret_cast<char *>(data));
+ for (size_t i(0); i != size; ++i)
+ bytes[i] = 0;
+}
extern "C" void Start(Baton *baton) {
struct _pthread self;
- baton->_pthread_set_self(&self);
+ $bzero(&self, sizeof(self));
+
+ // this code comes from _pthread_set_self
+ self.tsd[0] = &self;
+ baton->__pthread_set_self(&self);
+
+ int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
+ dlset(baton, pthread_create, "pthread_create");
pthread_t thread;
baton->pthread_create(&thread, NULL, &Routine, baton);
+ int (*pthread_join)(pthread_t, void **);
+ dlset(baton, pthread_join, "pthread_join");
+
void *result;
baton->pthread_join(thread, &result);
- baton->thread_terminate(baton->mach_thread_self());
-}
+ mach_port_t (*mach_thread_self)();
+ dlset(baton, mach_thread_self, "mach_thread_self");
-void *Routine(void *arg) {
- Baton *baton(reinterpret_cast<Baton *>(arg));
- void *handle(baton->dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
- void (*HandleServer)(pid_t) = reinterpret_cast<void (*)(pid_t)>(baton->dlsym(handle, "CYHandleServer"));
- HandleServer(baton->pid);
- return arg;
+ kern_return_t (*thread_terminate)(thread_act_t);
+ dlset(baton, thread_terminate, "thread_terminate");
+
+ baton->thread_terminate(baton->mach_thread_self());
}
if [[ -e test.cy ]]; then cycript test.cy; fi
install: cycript $(lib)cycript.$(dll)
- cp -p cycript /usr/bin
- cp -p $(lib)cycript.$(dll) /usr/lib
+ sudo cp -p cycript /usr/bin
+ sudo cp -p $(lib)cycript.$(dll) /usr/lib
+ # DOUG: this needs to be ported to GNUmakefile
+ sudo chgrp procmod /usr/bin/cycript
+ sudo chmod g+s /usr/bin/cycript
+
+# DOUG: this needs to be ported to GNUmakefile
+uninstall:
+ sudo rm -f /usr/bin/cycript /usr/lib/libcycript.dylib
.PHONY: all clean extra package control.tmp
Object_callAsFunction_toCYON should be implemented
[NSString stringWithString:""] crashes, on linux, not on mac
+
+replace procmod g+s with gdb's macosx_get_task_for_pid_rights
--- /dev/null
+#!/bin/bash
+
+shopt -s extglob
+
+hpp=$1
+object=$2
+name=$3
+sed=$4
+otool=$5
+lipo=$6
+nm=$7
+shift 7
+
+#shift 1
+#set /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.3.sdk/usr/include "$@"
+
+"$@"
+
+detailed=$(lipo -detailed_info "${object}")
+
+{
+
+echo '#include "Trampoline.hpp"'
+
+for arch in $(echo "${detailed}" | "${sed}" -e '/^architecture / { s/^architecture //; p; }; d;'); do
+ offset=$(echo "${detailed}" | "${sed}" -e '
+ /^architecture / { x; s/.*/0/; x; };
+ /^architecture '${arch}'$/ { x; s/.*/1/; x; };
+ x; /^1$/ { x; /^ *offset / { s/^ *offset //; p; }; x; }; x;
+ d;
+ ')
+
+ file=($("${otool}" -arch "${arch}" -l "${object}" | "${sed}" -e '
+ x; /^1$/ { x;
+ /^ *fileoff / { s/^.* //; p; };
+ /^ *filesize / { s/^.* //; p; };
+ x; }; x;
+
+ /^ *cmd LC_SEGMENT/ { x; s/.*/1/; x; };
+
+ d;
+ '))
+
+ fileoff=${file[0]}
+ filesize=${file[1]}
+
+ echo
+ echo "static const char ${name}_${arch}_data_[] = {"
+
+ od -v -t x1 -t c -j "$((offset + fileoff))" -N "${filesize}" "${object}" | "${sed}" -e '
+ /^[0-7]/ ! {
+ s@^ @// @;
+ s/\(....\)/ \1/g;
+ s@^ // @//@;
+ s/ *$//;
+ };
+
+ /^[0-7]/ {
+ s/^[^ ]*//;
+ s/ */ /g;
+ s/^ *//;
+ s/ $//;
+ s/ /,/g;
+ s/\([^,][^,]\)/0x\1/g;
+ s/$/,/;
+ /^,$/ ! { s/^/ /g; p; }; d;
+ };
+ '
+
+ echo "};"
+
+ echo
+ entry=$("${nm}" -arch "${arch}" "${object}" | "${sed}" -e '/ _Start$/ { s/ .*//; p; }; d;')
+ entry=${entry##*(0)}
+ echo "static size_t ${name}_${arch}_entry_ = 0x${entry:=0};"
+
+ echo
+ echo "/*"
+ "${otool}" -vVt -arch "${arch}" "${object}"
+ echo "*/"
+
+ echo
+ echo "static Trampoline ${name}_${arch}_ = {"
+ echo " ${name}_${arch}_data_,"
+ echo " sizeof(${name}_${arch}_data_),"
+ echo " ${name}_${arch}_entry_,"
+ echo "};"
+done
+
+} >"${hpp}"
+
+#rm -f "${object}"