When you come across <__NSXXXBlock__: 0xrandomnumber> while debugging a block in LLDB, how to locate the block

I don’t know what’s under the hood at the moment, please just follow the example below. If you’re curious, figure it out yourself and post a topic explaining the principles, thanks.

(lldb) po $x5
<__NSStackBlock__: 0x16fd26ac8>

(lldb) memory read --size 8 --format x 0x16fd26ac8
0x16fd26ac8: 0x00000001a0d11558 0x00000000c2000000
0x16fd26ad8: 0x00000001022d4638 0x00000001037ab4f0
0x16fd26ae8: 0x0000000126f4a1c0 0x0000000126ac9ae0
0x16fd26af8: 0x00000001821e7f00 0x0000000124d31400

Note, for arm64, the 2nd command is memory read --size 8, while for armv7/armv7s it should be memory read --size 4.

The value you get from 0x00000001022d4638 - ASLR offset is the address of the block. Go to this address in IDA or hopper then you’ll see the block implementation.

5 Likes

太感谢了!自己苦想一天都没什么头绪,这样一下就找到了,谢谢楼主!

根据Block的结构体,函数指针是void (*invoke)(void *, …); 所以楼主选了17个字节(也即第3个16Byte)的那个:

struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved;         // NULL
    unsigned long int size;         // sizeof(struct Block_literal_1)
    // optional helper functions
    void (*copy_helper)(void *dst, void *src);     // IFF (1<<25)
    void (*dispose_helper)(void *src);             // IFF (1<<25)
    // required ABI.2010.3.16
    const char *signature;                         // IFF (1<<30)
} *descriptor;
// imported variables
};
2 Likes

一行代码打印block信息工具了解一下

1 Like

block做属性怎么分析呢

@property (nonatomic, strong) void(^TestBlock)(NSString *);

self.TestBlock(@“123”);

0x100a6bf00: 6c 3a 00 73 65 6c 66 00 70 65 72 66 6f 72 6d 53 l:.self.performS

(lldb) p/x $x1
(unsigned long) $5 = 0x0000000100a6bef0
(lldb) memory read --format x 0x100a6bef0
0x100a6bef0: 0x74736554 0x636f6c42 0x7369006b 0x61757145
0x100a6bf00: 0x73003a6c 0x00666c65 0x66726570 0x536d726f
(lldb) memory read --size 8 --format x 0x100a6bef0
0x100a6bef0: 0x636f6c4274736554 0x617571457369006b
0x100a6bf00: 0x00666c6573003a6c 0x536d726f66726570
0x100a6bf10: 0x3a7267463656c65 0x6d726f6672657000
0x100a6bf20: 0x726f7463656c6553 0x6a624f687469773a
(lldb) x/4gx 0x0000000100a6bef0
0x100a6bef0: 0x636f6c4274736554 0x617571457369006b
0x100a6bf00: 0x00666c6573003a6c 0x536d726f66726570

这么大的地址看起来是栈上的地址吗

看起来不是

上面那个是我用xcode直接运行的一个例子,我想顺着想看怎么找到block的Imp.

我在我手机的lldb里面调试的这个值非常大。

#######这个是头文件的属性,看得到是一个block######
@property(copy, nonatomic) CDUnknownBlockType sendContent;

######这个是lldb,###########
(lldb) po/x (char*)$x1
“sendContent”
(lldb) po/x $x1
0x000000010675e808
(lldb) x/4gx 0x000000010675e808
0x10675e808: 0x746e6f43646e6573 0x4374657300746e65
0x10675e818: 0x6f697463656c6c6f 0x79614c776569566e
偏移一个指针8+两个int(4*2),那么0x6f697463656c6c6f就是这个地址了。。。
这个地址没搜到。。。感觉太大了。

我是这样想的,这个x1应该是这个get方法的地址吧。。。返回值才是这个block的函数地址。。。需要获取到这个返回值才行,怎么获取返回值呢。张总能不能指点一二

CompilerRT里有Block运行时,里面有用来查看Block信息的C接口我记得

https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/BlocksRuntime/Block_private.h

感谢 张总 我再研究研究

我自己犯蠢了。。。

这个block是个属性,直接调用对象的get方法就能拿到这个属性的地址了。。。
再偏移16个字节就是IMP的地址了。。。。

完结。。。

(lldb) po $x0
<TestObject: 0x2807b05f0>
(lldb) po $x1
4310134979
(lldb) po (char)$x1*
“TestBlock”
(lldb) po [$x0 TestBlock]
<NSGlobalBlock: 0x100e78028>
signature: "v16@?0@“NSString"8”
invoke : 0x100e75944 (/private/var/containers/Bundle/Application/16652EAA-FDB0-40F3-ADA7-887649259FD1/TestSign.app/TestSign`__29-[ViewController viewDidLoad]_block_invoke)

(lldb) x/4gx 0x100e78038
0x100e78038: 0x0000000100e75944 0x0000000100e78008
0x100e78048: 0x0000000207146280 0x00000000000007c8
(lldb) br set -a 0x0000000100e75944
Breakpoint 2: where = TestSign`__29-[ViewController viewDidLoad]_block_invoke at ViewController.m:23, address = 0x0000000100e75944