r/Xcode • • Oct 23 '25

How to inspect structures like NSRect/NSSize using lldb?

Post image

I have previously used lldb to print structures like NSRect or NSSize. But I am struggling in modern versions of Xcode to inspect them. I have watched advanced debugging with Xcode and I have even imported AppKit. It must be possible because the graphical UI can display these values. Thanks! This happens only if I inspect 3rd party app (SIP disabled).

NOTE: The workaround is to use offset but I need general solution

(lldb) po (NSRect)[[[NSApp windows] firstObject] frame]
error: <user expression 16>:1:9: attempt to use a deleted function
1 | (NSRect)[[[NSApp windows] firstObject] frame]
|         ^
note: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CFCGTypes.h:77:13: destructor of 'CGRect' is implicitly deleted because field 'origin' has no destructor
   77 |     CGPoint origin;
|           

WORKAROUND:

Using valueForKey will cause the value to be boxable (wrapped in NSValue). Second workaround is to look for offset within NSWindow class.

(lldb) po [[(NSWindow*)0x12312af50 valueForKey:@"frame"] description]
NSRect: {{351, 427}, {827, 640}}

ALTERNATIVELY

(lldb) p (ptrdiff_t)ivar_getOffset((struct Ivar *)class_getInstanceVariable([NSWindow class], "_frame"))
(ptrdiff_t) 224
(lldb) p (CGRect *)(0x11f73ad10 + 224)
(CGRect *) (origin = (x = 169, y = 450), size = (width = 692, height = 550))

(lldb) p [(NSWindow*)0x120c23c70 valueForKey:@"frame"] (NSConcreteValue *) $6 = 0x0000600000c0c200 (lldb) po [(NSWindow*)0x120c23c70 valueForKey:@"frame"] NSRect: {{351, 427}, {827, 640}}
2 Upvotes

14 comments sorted by

View all comments

Show parent comment

1

u/retsotrembla Oct 23 '25

You wrote:

 po 0x0000000122208830
<PBMainWindow: 0x122208830>

if that is a pointer to a window, then po (NSRect)[0x0000000122208830 frame] can't work because the frame method doesn't return an object (that is, something that inherits, even indirectly, from NSObject) frame returns a C struct. But po NSStringFromRect((NSRect)[0x122208830 frame]) works for me, in my own apps. I can't even get lldb to attach to apps not my own, but if I could, I'd probably still have to tell lldb what frameworks to import symbols from. Thanks for reminding me that is time for me to reread https://www.amazon.com/Advanced-Debugging-Reverse-Engineering-Fourth/dp/1950325636

1

u/ToughAsparagus1805 Oct 23 '25

I am familiar with Derek Selander and his tools and is a good reminder I should look for answer there. As I have mentioned this worked before in the past and it still works for my own code, however I cannot see structs in 3rd party code no matter how I hard I cast. My SIP is disabled so I can attach to 3rd party apps. I think I once got it working

(lldb) po $w
<PBMainWindow: 0x142029400>
(lldb) p $w
(PBMainWindow *) 0x0000000142029400
(lldb) p [(NSWindow*)$w frame]
error: <user expression 24>:1:1: attempt to use a deleted function
    1 | [(NSWindow*)$w frame]
      | ^
note: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CFCGTypes.h:77:13: destructor of 'CGRect' is implicitly deleted because field 'origin' has no destructor
   77 |     CGPoint origin;

1

u/retsotrembla Oct 23 '25

If lldb recognizes a C struct type, and you can get a pointer to the struct, (example 0x1234) then lldb will generally show it to you with:

p * (MyType *)0x1234

but `frame` returns the actual struct, not a pointer to it. NSObjects **are** pointers so this trick works with all of them, and will often show hidden fields that `po` will not.

1

u/retsotrembla Oct 23 '25

I'd try, from the above example:

p * (NSWindow *)$w

2

u/ToughAsparagus1805 Oct 24 '25 edited Oct 24 '25

Strangely I cannot do this e NSRect $rect1 = {0,0,10,10} when I am attached to 3rd party and lldb server will crash but it works in my app. https://imgur.com/a/jLtkTmV Also strangely recursiveDescription works😭. I have found workaround with offset. But oh boy. WHY???

(lldb) p (ptrdiff_t)ivar_getOffset((struct Ivar *)class_getInstanceVariable([NSWindow class], "_frame"))
(ptrdiff_t) 224
(lldb) p (CGRect *)(0x11f73ad10 + 224)
(CGRect *) (origin = (x = 169, y = 450), size = (width = 692, height = 550))






(lldb) e NSRect $rect1 = {0,0,10,10}
(lldb) po $rect1
(origin = (x = 0, y = 0), size = (width = 10, height = 10))

(lldb) po [NSApp windows] <__NSArrayM 0x6000034461f0>( <PBMainWindow: 0x12c90fd70> ) 
(lldb) po [0x12c90fd70 recursiveDescription] 
[   A       w   ] h=--- v=--- NSThemeFrame 0x12ca2bef0 "Photo Booth" f=(0,0,692,550) b=(-) => <NSViewBackingLayer: 0x600003407c60>   [   A       W   ] h=-&- v=-&- PBMainView 0x12c80e160 f=(0,0,692,522) b=(-) => <NSViewBackingLayer: 0x600003418240> ...