You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LLDB中打印传递给Cocoa方法的NSRect参数?

问题:在LLDB中打印NSRect结构体参数的方法

调试macOS程序时,我需要打印传递给-[NSView setNeedsDisplayInRect:]的NSRect参数,断点能正常命中,但无法正常打印该参数。NSRect本质是包含四个double的结构体,为此我编写了一段测试程序(使用Xcode 12.5编译,在M1处理器的Mac mini上运行)来复现问题:

#include <stdio.h>

typedef struct {
    double a;
    double b;
    double c;
    double d;
} MyRect1;

typedef struct {
    double a;
    double b;
    double c;
    long d;
} MyRect2;

void foo(MyRect1 rect) {
    printf("%f\n", rect.a);
}

void bar(MyRect2 rect) {
    printf("%f\n", rect.a);
}

int main(int argc, const char * argv[]) {
    MyRect1 rect1 = { 1, 2, 3, 4 };
    MyRect2 rect2 = { 1, 2, 3, 4 };
    foo(rect1);
    bar(rect2);
    return 0;
}

根据ARM64架构过程调用标准:

如果参数类型是大于16字节的复合类型,则参数会被复制到调用者分配的内存中,并替换为指向该副本的指针。

我原本预期foo()和bar()都会以结构体指针作为参数调用。测试中bar()里的MyRect2确实可以通过*(MyRect2 *)$arg1正常打印,但foo()里的MyRect1执行同样操作会报错:

error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory

两个结构体大小均为32字节,仅最后一个成员类型不同。


解决方法

方法1:直接打印LLDB解析好的变量

LLDB在栈帧信息中已经自动解析出了结构体的值(参考bt输出里的rect=(a = 1, b = 2, c = 3, d = 4)),直接打印变量名即可:

(lldb) p rect
(MyRect1) $0 = (a = 1, b = 2, c = 3, d = 4)

针对-[NSView setNeedsDisplayInRect:],直接执行:

(lldb) p rect

方法2:手动从浮点寄存器拼接结构体

对于全double成员的结构体,ARM64 ABI会直接用浮点寄存器传递(四个double对应d0-d3寄存器),可以手动拼接结构体:

(lldb) expr MyRect1 {.a = $d0, .b = $d1, .c = $d2, .d = $d3}
(MyRect1) $1 = (a = 1, b = 2, c = 3, d = 4)

对于NSRect(结构为{NSPoint origin; NSSize size;}),可以用:

(lldb) expr NSRect {.origin.x = $d0, .origin.y = $d1, .size.width = $d2, .size.height = $d3}

问题原因说明

ARM64 ABI对全浮点成员的结构体有特殊处理规则:当结构体所有成员都是浮点类型(如double)且大小不超过8个浮点寄存器(64字节)时,会直接用浮点寄存器传递参数,而非放到内存再传递指针。MyRect1四个double刚好占4个浮点寄存器(d0-d3),因此$arg1并不是指向结构体的有效指针,自然无法通过指针解引用读取。而MyRect2包含整数成员,不符合全浮点条件,因此采用内存+指针的传递方式,$arg1是有效指针。

内容的提问来源于stack exchange,提问作者user11253534

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:50:40