In order to debug a macOS program I need to print the NSRect that is passed to -[NSView:setNeedsDisplayInRect:]. I can set a breakpoint in that method, but I have trouble printing its argument.
NSRect is “essentially” a struct of four doubles. In order to demonstrate the problem I have written a small self-contained program. It is compiled with Xcode 12.5 and run on a Mac mini with M1 processor.
#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;
}
The Procedure Call Standard for the ARM 64-bit Architecture (AArch64) states that
If the argument type is a Composite Type that is larger than 16 bytes, then the argument is copied to memory allocated by the caller and the argument is replaced by a pointer to the copy.
Therefore I would expect that both foo() and bar() are called with a pointer to the structure as the single argument. Setting a breakpoint in bar() and casting the first argument to MyRect2 * indeed produces the expected result:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100003e94 argtest2`bar(rect=(a = 1, b = 2, c = 3, d = 4)) at main.c:22:29
frame #1: 0x0000000100003f34 argtest2`main(argc=1, argv=0x000000016fdff428) at main.c:29:9
frame #2: 0x000000019871d430 libdyld.dylib`start + 4
(lldb) expr -- *(MyRect2 *)$arg1
(MyRect2) $0 = (a = 1, b = 2, c = 3, d = 4)
However, this does not work with MyRect1 in foo():
lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100003e64 argtest2`foo(rect=(a = 1, b = 2, c = 3, d = 4)) at main.c:18:29
frame #1: 0x0000000100003f1c argtest2`main(argc=1, argv=0x000000016fdff428) at main.c:28:9
frame #2: 0x000000019871d430 libdyld.dylib`start + 4
(lldb) expr -- *(MyRect1 *)$arg1
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
Note that both structs have the same size (32 bytes), and differ only in the last member.
Question: How can I print the argument passed to a function in lldb if that argument is of type NSRect (or any other struct of four doubles)?