-
-
Save faimin/3b3070926b8cda8587b626301baa5980 to your computer and use it in GitHub Desktop.
修改block的实现,先打印参数,再输出原有实现
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import "ffi.h" | |
NSMutableArray *g_allocations; | |
ffi_cif g_cif; | |
ffi_closure *g_closure; | |
void *g_replacement_invoke; | |
void *g_origin_invoke; | |
id g_block; | |
enum { | |
BLOCK_HAS_COPY_DISPOSE = (1 << 25), | |
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code | |
BLOCK_IS_GLOBAL = (1 << 28), | |
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE | |
BLOCK_HAS_SIGNATURE = (1 << 30), | |
}; | |
typedef struct __block_descriptor { | |
size_t reserved; | |
size_t Block_size; | |
void *rest[1]; | |
}__block_descriptor; | |
typedef struct __block_impl { | |
void *isa; | |
int Flags; | |
int Reserved; | |
void *FuncPtr; | |
__block_descriptor *descriptor; | |
}__block_impl; | |
const char *block_type_encode_string(id blk) { | |
__block_impl *block_impl = (__bridge void *)blk; | |
__block_descriptor *descriptor = block_impl->descriptor; | |
assert(block_impl->Flags & BLOCK_HAS_SIGNATURE); | |
int index = 0; | |
if(block_impl->Flags & BLOCK_HAS_COPY_DISPOSE) | |
index += 2; | |
return descriptor->rest[index]; | |
} | |
void invoke_original_block(void* ret, void **args) { | |
if (g_origin_invoke) { | |
ffi_call(&g_cif, g_origin_invoke, ret, args); | |
} | |
} | |
static void ffi_clousure_func(ffi_cif *cif, void *ret, void **args, void *user_data) { | |
int i = *((int *)args[1]); | |
NSString *str = (__bridge NSString *)(*((void **)args[2])); | |
NSLog(@"%d,%@", i, str); | |
invoke_original_block(ret, args); | |
} | |
const char * size_and_alignment(const char *str, NSUInteger *sizep, NSUInteger *alignp, long *len) { | |
const char *out = NSGetSizeAndAlignment(str, sizep, alignp); | |
if(len) | |
*len = out - str; | |
while(isdigit(*out)) | |
out++; | |
return out; | |
} | |
static int arg_count(const char *str) { | |
int argcount = -1; // return type is the first one | |
while(str && *str) { | |
str = size_and_alignment(str, NULL, NULL, NULL); | |
argcount++; | |
} | |
return argcount; | |
} | |
void * allocate(size_t howmuch) { | |
NSMutableData *data = [NSMutableData dataWithLength:howmuch]; | |
[g_allocations addObject: data]; | |
return [data mutableBytes]; | |
} | |
ffi_type * ffi_arg_for_encode(const char *str) { | |
#define SINT(type) do { \ | |
if(str[0] == @encode(type)[0]) \ | |
{ \ | |
if(sizeof(type) == 1) \ | |
return &ffi_type_sint8; \ | |
else if(sizeof(type) == 2) \ | |
return &ffi_type_sint16; \ | |
else if(sizeof(type) == 4) \ | |
return &ffi_type_sint32; \ | |
else if(sizeof(type) == 8) \ | |
return &ffi_type_sint64; \ | |
else \ | |
{ \ | |
NSLog(@"Unknown size for type %s", #type); \ | |
abort(); \ | |
} \ | |
} \ | |
} while(0) | |
#define UINT(type) do { \ | |
if(str[0] == @encode(type)[0]) \ | |
{ \ | |
if(sizeof(type) == 1) \ | |
return &ffi_type_uint8; \ | |
else if(sizeof(type) == 2) \ | |
return &ffi_type_uint16; \ | |
else if(sizeof(type) == 4) \ | |
return &ffi_type_uint32; \ | |
else if(sizeof(type) == 8) \ | |
return &ffi_type_uint64; \ | |
else \ | |
{ \ | |
NSLog(@"Unknown size for type %s", #type); \ | |
abort(); \ | |
} \ | |
} \ | |
} while(0) | |
#define INT(type) do { \ | |
SINT(type); \ | |
UINT(unsigned type); \ | |
} while(0) | |
#define COND(type, name) do { \ | |
if(str[0] == @encode(type)[0]) \ | |
return &ffi_type_ ## name; \ | |
} while(0) | |
#define PTR(type) COND(type, pointer) | |
#define STRUCT(structType, ...) do { \ | |
if(strncmp(str, @encode(structType), strlen(@encode(structType))) == 0) \ | |
{ \ | |
ffi_type *elementsLocal[] = { __VA_ARGS__, NULL }; \ | |
ffi_type **elements = allocate(sizeof(elementsLocal)); \ | |
memcpy(elements, elementsLocal, sizeof(elementsLocal)); \ | |
\ | |
ffi_type *structType = allocate(sizeof(*structType)); \ | |
structType->type = FFI_TYPE_STRUCT; \ | |
structType->elements = elements; \ | |
return structType; \ | |
} \ | |
} while(0) | |
SINT(_Bool); | |
SINT(signed char); | |
UINT(unsigned char); | |
INT(short); | |
INT(int); | |
INT(long); | |
INT(long long); | |
PTR(id); | |
PTR(Class); | |
PTR(SEL); | |
PTR(void *); | |
PTR(char *); | |
PTR(void (*)(void)); | |
COND(float, float); | |
COND(double, double); | |
COND(void, void); | |
ffi_type *CGFloatFFI = sizeof(CGFloat) == sizeof(float) ? &ffi_type_float : &ffi_type_double; | |
STRUCT(CGRect, CGFloatFFI, CGFloatFFI, CGFloatFFI, CGFloatFFI); | |
STRUCT(CGPoint, CGFloatFFI, CGFloatFFI); | |
STRUCT(CGSize, CGFloatFFI, CGFloatFFI); | |
#if !TARGET_OS_IPHONE | |
STRUCT(NSRect, CGFloatFFI, CGFloatFFI, CGFloatFFI, CGFloatFFI); | |
STRUCT(NSPoint, CGFloatFFI, CGFloatFFI); | |
STRUCT(NSSize, CGFloatFFI, CGFloatFFI); | |
#endif | |
NSLog(@"Unknown encode string %s", str); | |
abort(); | |
} | |
ffi_type ** args_with_encode_string(const char *str, int *out_count) { | |
int count = arg_count(str); | |
ffi_type **arg_types = allocate(count * sizeof(*arg_types)); | |
int i = -1; // 第一个是返回值,需要排除 | |
while(str && *str) { | |
const char *next = size_and_alignment(str, NULL, NULL, NULL); | |
if(i >= 0) | |
arg_types[i] = ffi_arg_for_encode(str); | |
i++; | |
str = next; | |
} | |
*out_count = count; | |
return arg_types; | |
} | |
void prep_cif() { | |
int args_count; | |
const char *str = block_type_encode_string(g_block); | |
ffi_type **arg_types = args_with_encode_string(str, &args_count); | |
ffi_status status = ffi_prep_cif(&g_cif, FFI_DEFAULT_ABI, args_count, ffi_arg_for_encode(str), arg_types); | |
if(status != FFI_OK) { | |
NSLog(@"Got result %ld from ffi_prep_cif", (long)status); | |
abort(); | |
} | |
} | |
void prep_closure() { | |
prep_cif(); | |
g_closure = ffi_closure_alloc(sizeof(ffi_closure), &g_replacement_invoke); | |
ffi_status status = ffi_prep_closure_loc(g_closure, &g_cif, ffi_clousure_func, NULL, g_replacement_invoke); | |
if(status != FFI_OK) { | |
NSLog(@"ffi_prep_closure returned %d", (int)status); | |
abort(); | |
} | |
g_origin_invoke = ((__bridge __block_impl *)g_block)->FuncPtr; | |
((__bridge __block_impl *)g_block)->FuncPtr = g_replacement_invoke; | |
} | |
void HookBlockToPrintArguments(id blk) { | |
g_block = blk; | |
prep_closure(); | |
} | |
#pragma mark - 第二种实现方式 | |
//static void (*orig_func)(void *v ,int i, NSString *str); | |
//void hookFunc(void *v ,int i, NSString *str) { | |
// NSLog(@"%d,%@", i, str); | |
// orig_func(v,i,str); | |
//} | |
//void HookBlockToPrintArguments(id blk) { | |
// __block_impl *ptr = (__bridge __block_impl *)blk; | |
// orig_func = ptr->FuncPtr; | |
// ptr->FuncPtr = &hookFunc; | |
//} | |
int main(int argc, const char * argv[]) { | |
void (^blk)(int, NSString *) = ^void(int i, NSString *str) { | |
NSLog(@"original invoke"); | |
}; | |
HookBlockToPrintArguments(blk); | |
blk(1,@"aaa"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment