一行代码获取Block的签名和虚拟内存地址:
NSString *blockDescription = [ZLJBlockPrinter printBlock:_shareBlock];
NSLog(@"%@",blockDescription);
返回效果
kSignature:<NSMethodSignature: 0x281aaa9c0>
number of arguments = 4
frame size = 224
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v) 'v'
flags {}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset = 0, size = 0}
argument 0: -------- -------- -------- --------
type encoding (@) '@?'
flags {isObject, isBlock}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
argument 1: -------- -------- -------- --------
type encoding (B) 'B'
flags {}
modifiers {}
frame {offset = 8, offset adjust = 0, size = 8, size adjust = -7}
memory {offset = 0, size = 1}
argument 2: -------- -------- -------- --------
type encoding (i) 'i'
flags {isSigned}
modifiers {}
frame {offset = 16, offset adjust = 0, size = 8, size adjust = -4}
memory {offset = 0, size = 4}
argument 3: -------- -------- -------- --------
type encoding (@) '@"NSString"'
flags {isObject}
modifiers {}
frame {offset = 24, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
class 'NSString'
返回显示4个参数 要减去1个 return
所以下面得出 callback 参数为:
^(BOOL isok, int code, NSString*msg) {
}
查看官方文档访问点击查看更多对照表信息
//
// ZLJPrinter.h
// SMS
//
// Created by Mu on 2019/8/1.
//
#import <Foundation/Foundation.h>
#import <mach-o/dyld.h>
#import <mach/mach.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZLJPrinter : NSObject
+ (NSString *)printBlock:(id)aBlock;
+ (NSString *)callStackSymbolsLocateInImages:(NSArray <NSString *>*)images;
@end
NS_ASSUME_NONNULL_END
/* block 内存结构
struct Block_literal_1 {
void *isa; //16byte initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags; //8byte
int reserved; //8byte
void (*invoke)(void *, ...); //16byte
struct Block_descriptor_1 { //16byte
unsigned long int reserved; //16byte NULL
unsigned long int size; //16byte sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); //16byte IFF (1<<25)
void (*dispose_helper)(void *src); //16byte IFF (1<<25)
// required ABI.2010.3.16
const char *signature; //16byte IFF (1<<30)
} *descriptor;
// imported variables
};
struct BlockLiteral {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct BlockDescriptor *descriptor;
};
struct BlockDescriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy_helper)(void *dst, void *src);
void (*dispose_helper)(void *src);
const char *signature;
};
*/
//
// ZLJPrinter.m
// SMS
//
// Created by Mu on 2019/8/1.
//
#import "ZLJPrinter.h"
@implementation ZLJPrinter
+ (NSString *)callStackSymbolsLocateInImages:(NSArray <NSString *>*)images{
NSArray <NSString *>*preSetImages = [@[
@"libdyld.dylib",
@"UIKit",
@"GraphicsServices",
@"CoreFoundation",
@"Foundation",
] mutableCopy];
NSMutableDictionary <NSString *, NSNumber *>*baseAddrDic = [[NSMutableDictionary alloc]init];
for(int i = 0; i < _dyld_image_count(); i++)
{
intptr_t base_addr = _dyld_get_image_vmaddr_slide(i);
const char *name = _dyld_get_image_name(i);
NSString *nameStr = [NSString stringWithUTF8String:name];
if ([images containsObject:[nameStr lastPathComponent]] ||
[preSetImages containsObject:[nameStr lastPathComponent]]) {
[baseAddrDic setObject:@(base_addr) forKey:[nameStr lastPathComponent]];
}
}
NSArray <NSString *>*syms = [NSThread callStackSymbols];
NSMutableString *retStr = [[NSMutableString alloc]init];
[retStr appendString:@"\n\n/***ZLJ CallStackSymbols Start***/\n"];
for (NSString *sym in syms) {
NSMutableArray <NSString *>*symUnits = [[sym componentsSeparatedByString:@" "] mutableCopy];
while ([symUnits containsObject:@""]) {
[symUnits removeObject:@""];
}
if (symUnits.count >= 3 && [symUnits[2] hasPrefix:@"0x"]) {
char *symVMAddrStr = (char *)symUnits[2].UTF8String;
char *endPtr;
NSInteger symVMAddr = strtol(symVMAddrStr, &endPtr, 16);
if ([baseAddrDic.allKeys containsObject:symUnits[1]]) {
NSInteger symFileAddr = symVMAddr - [baseAddrDic objectForKey:symUnits[1]].integerValue;
[retStr appendFormat:@"%@ symFileAddr 0x%lx\n", sym, symFileAddr];
}else{
[retStr appendFormat:@"%@\n", sym];
}
}else{
[retStr appendFormat:@"%@\n", sym];
}
}
[retStr appendString:@"/***ZLJ CallStackSymbols End***/\n\n"];
NSLog(@"%@",retStr);
return retStr;
}
+ (NSString *)printBlock:(id)aBlock{
if (!([aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")] ||
[aBlock isKindOfClass:NSClassFromString(@"__NSMallocBlock__")] ||
[aBlock isKindOfClass:NSClassFromString(@"__NSStackBlock__")] )) {
return @"ZLJBlockPrinter Error: Not A Block!";
}
uint64_t blockInMemory[4]; //block 在内存中的前4个uint64_t
uint64_t descriptor[5]; //block的descriptor 在内存中的前5个uint64_t
char *signatureCStr;
NSMethodSignature *blockSignature;
void *aBlockPtr = (__bridge void *)(aBlock);
memcpy(blockInMemory, (void *)aBlockPtr, sizeof(blockInMemory));
memcpy(descriptor, (void *)blockInMemory[3], sizeof(descriptor));
BOOL hasSignature = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 30)) != 0;
if (!hasSignature) {
return @"ZLJBlockPrinter: Block Do Not Have Signature!";
}
BOOL hasCopyDisposeHelper = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 25)) != 0;
if (hasCopyDisposeHelper) {
signatureCStr = (char *)descriptor[4];
}else{
signatureCStr = (char *)descriptor[2];
}
blockSignature = [NSMethodSignature signatureWithObjCTypes:signatureCStr];
NSString *retStr = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide:0x%llx\nBlockSignature:%@",
aBlock,
blockInMemory[2],
blockSignature.debugDescription];
NSLog(@"%@",retStr);
return retStr;
}
//+ (NSString *)printBlock:(id)aBlock inImage:(nullable NSString *)imageName{
//
// if (!([aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")] ||
// [aBlock isKindOfClass:NSClassFromString(@"__NSMallocBlock__")] ||
// [aBlock isKindOfClass:NSClassFromString(@"__NSStackBlock__")] )) {
// return @"ZLJBlockPrinter Error: Not A Block!";
// }
//
// uint64_t blockInMemory[4]; //block 在内存中的前4个uint64_t
// uint64_t descriptor[5]; //block的descriptor 在内存中的前5个uint64_t
// char *signatureCStr;
// NSMethodSignature *blockSignature;
//
// void *aBlockPtr = (__bridge void *)(aBlock);
// memcpy(blockInMemory, (void *)aBlockPtr, sizeof(blockInMemory));
// memcpy(descriptor, (void *)blockInMemory[3], sizeof(descriptor));
//
// BOOL hasSignature = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 30)) != 0;
// if (!hasSignature) {
// return @"ZLJBlockPrinter: Block Do Not Have Signature!";
// }
//
//
// BOOL hasCopyDisposeHelper = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 25)) != 0;
//
// if (hasCopyDisposeHelper) {
// signatureCStr = (char *)descriptor[4];
// }else{
// signatureCStr = (char *)descriptor[2];
// }
// blockSignature = [NSMethodSignature signatureWithObjCTypes:signatureCStr];
//
//
// uint64_t block_file_slide = 0;
// if (imageName.length && [aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")]) {
// NSInteger image_vmaddr_slide = 0;
// for(int i = 0; i < _dyld_image_count(); i++)
// {
// const char *name = _dyld_get_image_name(i);
// NSString *nameStr = [NSString stringWithUTF8String:name];
// if ([nameStr containsString:imageName]) {
// image_vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
// break;
// }
// }
// block_file_slide = blockInMemory[2] - image_vmaddr_slide;
// }
//
// NSString *ret = nil;
// if (imageName.length && [aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")]) {
// ret = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide(Check This Address In LLDB):0x%llx\nBlockFileSlide(Jump To This Address In IDA):0x%llx\nBlockSignature:%@", [aBlock class], blockInMemory[2], block_file_slide, blockSignature.debugDescription];
// }else{
// ret = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide(Check This Address In LLDB):0x%llx\nBlockSignature:%@", aBlock, blockInMemory[2], blockSignature.debugDescription];
// }
//
// return ret;
//}
@end