X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/f1b5a47ffa92e12d17571d350a567e2035d75039..83646644cade2e27f9df70ca0d5e730c7c84b0ab:/ObjectiveC/Library.mm diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index dddbd95..238fb2b 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -35,6 +35,11 @@ #include #endif +#ifdef __APPLE__ +#include +#include +#endif + #include "Error.hpp" #include "JavaScript.hpp" #include "String.hpp" @@ -2189,6 +2194,76 @@ static void ObjectiveC_Constants_getPropertyNames(JSContextRef context, JSObject JSPropertyNameAccumulatorAddName(names, CYJSString("nil")); } +static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) { + *data = reinterpret_cast(address); + return KERN_SUCCESS; +} + +struct CYChoice { + Class query_; + JSContextRef context_; + JSObjectRef results_; +}; + +struct CYObjectStruct { + Class isa_; +}; + +static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) { + CYChoice *choice(reinterpret_cast(baton)); + JSContextRef context(choice->context_); + + for (unsigned i(0); i != count; ++i) { + vm_range_t &range(ranges[i]); + void *data(reinterpret_cast(range.address)); + size_t size(range.size); + + if (size < sizeof(CYObjectStruct)) + continue; + + uintptr_t *pointers(reinterpret_cast(data)); +#ifdef __arm64__ + Class isa(reinterpret_cast(pointers[0] & 0x1fffffff8)); +#else + Class isa(reinterpret_cast(pointers[0])); +#endif + + if (isa != choice->query_) + continue; + CYArrayPush(context, choice->results_, CYCastJSValue(context, reinterpret_cast(data))); + } +} + +static JSValueRef choose(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { + if (count != 1) + throw CYJSError(context, "choose() takes a class argument"); + + CYPool pool; + Class _class(CYCastNSObject(&pool, context, arguments[0])); + + vm_address_t *zones(NULL); + unsigned size(0); + kern_return_t error(malloc_get_all_zones(0, &CYReadMemory, &zones, &size)); + _assert(error == KERN_SUCCESS); + + JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array"))); + JSObjectRef results(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL)); + + CYChoice choice; + choice.query_ = _class; + choice.context_ = context; + choice.results_ = results; + + for (unsigned i(0); i != size; ++i) { + const malloc_zone_t *zone(reinterpret_cast(zones[i])); + if (zone == NULL || zone->introspect == NULL) + continue; + zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_); + } + + return results; +} CYCatch(NULL) } + #ifdef __APPLE__ #if defined(__i386__) || defined(__x86_64__) #define OBJC_MAX_STRUCT_BY_VALUE 8 @@ -2284,7 +2359,7 @@ JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _cla return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, &signature, &cif, function); } -static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { +static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[]) { if (count < 2) throw CYJSError(context, "too few arguments to objc_msgSend"); @@ -2320,6 +2395,10 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje _cmd = CYCastSEL(context, arguments[1]); return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized); +} + +static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { + return $objc_msgSend(context, object, _this, count, arguments); } CYCatch(NULL) } static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { @@ -2327,7 +2406,7 @@ static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef obje setup[0] = _this; setup[1] = object; memcpy(setup + 2, arguments, sizeof(JSValueRef) * count); - return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception); + return $objc_msgSend(context, NULL, NULL, count + 2, setup); } CYCatch(NULL) } static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { @@ -2508,9 +2587,9 @@ static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjec return CYCastJSValue(context, sel_getName(internal->GetValue())); } CYCatch(NULL) } -static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { +static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception); -} CYCatch(NULL) } +} static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { Selector_privateData *internal(reinterpret_cast(JSObjectGetPrivate(_this))); @@ -2734,8 +2813,13 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry { ObjectiveC_Protocols_ = JSClassCreate(&definition); #ifdef __APPLE__ +// XXX: this is horrible; there has to be a better way to do this +#ifdef __LP64__ + class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}32@0:8@16^{OpaqueJSContext=}24"); +#else class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}16@0:4@8^{OpaqueJSContext=}12"); #endif +#endif } CYPoolCatch() } void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { @@ -2812,6 +2896,10 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum); #endif +#ifdef __APPLE__ + CYSetProperty(context, all, CYJSString("choose"), &choose, kJSPropertyAttributeDontEnum); +#endif + CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum); JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);