Last active
October 22, 2020 13:50
-
-
Save Skifary/5715a815d1d356c8fdc178b31d9be4fa 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; | |
} |
前排膜拜大佬。
膜拜 不得不服
膜拜大神!!!
新增第二种实现方式
前排膜拜大佬。
前排膜拜大佬。
前排膜拜大佬。
前排膜拜大佬。
后排膜拜大佬。
再次膜拜大佬。
但其实这只实现了特定的block替换,如果block的参数不确定,或者把int跟String一换,这个程序就崩了。我感觉提问者的意思应该是写一个通用的方法。而不是只能换这一种block。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
太牛比了,膜拜,已粉。