4

Is it possible to access arguments for caller and caller-of-caller via Obj-C runtime. I only found:

NSLog(@"%@", [NSThread callStackSymbols]);

I know it is possible, but is there any instruments (API) ?

UPDATE 1:

Maybe we can analyze [NSThread callStackSymbols] to determine number of arguments in each nested call. And then walk thru the stack ...

UPDATE 2:

I am going deeper, [NSThread callStackSymbols] is:

0   MyApp            0x00009ee5 -[HNPViewController mapView:didDeselectAnnotationView:] + 117,
1   MapKit           0x00404d12 -[MKMapView annotationContainer:didDeselectAnnotationView:] + 100,
2   MapKit           0x00411f90 -[MKAnnotationContainerView _deselectAnnotationViewWithAnimation:tellDelegate:] + 204,
3   MapKit           0x003fef87 -[MKMapView handleTap:] + 544,
4   UIKit            0x007c485a _UIGestureRecognizerSendActions + 139,
5   UIKit            0x007c399b -[UIGestureRecognizer _updateGestureWithEvent:] + 333,
6   UIKit            0x007c50df -[UIGestureRecognizer _delayedUpdateGesture] + 46,
7   UIKit            0x007c7d2d ___UIGestureRecognizerUpdate_block_invoke_0543 + 57,
8   UIKit            0x007c7cac _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 331,
9   UIKit            0x007bfa28 _UIGestureRecognizerUpdate + 1348,
10  CoreFoundation   0x01870afe __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30,
11  CoreFoundation   0x01870a3d __CFRunLoopDoObservers + 381,
12  CoreFoundation   0x0184e7c2 __CFRunLoopRun + 1106,
13  CoreFoundation   0x0184df44 CFRunLoopRunSpecific + 276,
14  CoreFoundation   0x0184de1b CFRunLoopRunInMode + 123,
15  GraphicsServices 0x029097e3 GSEventRunModal + 88,
16  GraphicsServices 0x02909668 GSEventRun + 104,
17  UIKit            0x004f9ffc UIApplicationMain + 1211,
18  MyApp            0x0000281d main + 141,
19  MyApp            0x00002745 start + 53

And I am printing (id)*(&mapView+i) where mapView is first argument and i = 0 .. N:

    (id)*(&mapView+0)  = 0x09e55670 <MKMapView: 0x9e55670; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = TM+BM; layer = <CALayer: 0x9e55720>>
    (id)*(&mapView+1)  = 0x0046ec8f [no Objective-C description available]
    (id)*(&mapView+2)  = 0x09e4bd90 <HNPViewController: 0x9e4bd90>
    (id)*(&mapView+3)  = 0xe9a8b620 [no Objective-C description available]
    (id)*(&mapView+4)  = 0x00000020 [no Objective-C description available]
    (id)*(&mapView+5)  = 0x0046ec8f [no Objective-C description available]
    (id)*(&mapView+6)  = 0x00000054 [no Objective-C description available]
    (id)*(&mapView+7)  = 0xbfffda28 [no Objective-C description available]
    (id)*(&mapView+8)  = 0x00404d12 [no Objective-C description available]
    (id)*(&mapView+9)  = 0x09e4bd90 <HNPViewController: 0x9e4bd90>
    (id)*(&mapView+10) = 0x0046ec8f [no Objective-C description available]
    (id)*(&mapView+11) = 0x09e55670 <MKMapView: 0x9e55670; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = TM+BM; layer = <CALayer: 0x9e55720>>
    (id)*(&mapView+12) = 0x14346af0 <MKUserLocationView: 0x14346af0; frame = (1.34202e+06 3.24204e+06; 23 23); layer = <MKUserLocationLayer: 0x1433b8f0>> accuracy:-1.000000 +37.78583400, -122.40641700
    (id)*(&mapView+13) = 0x14346af0 <MKUserLocationView: 0x14346af0; frame = (1.34202e+06 3.24204e+06; 23 23); layer = <MKUserLocationLayer: 0x1433b8f0>> accuracy:-1.000000 +37.78583400, -122.40641700
    (id)*(&mapView+14) = 0x00aa61d8 [no Objective-C description available]
    (id)*(&mapView+15) = 0x00000000 <nil>
    (id)*(&mapView+16) = 0x00411ed2 [no Objective-C description available]
    (id)*(&mapView+17) = 0x0aab0020 <MKAnnotationContainerView: 0xaab0020; frame = (0 0; 8.38861e+06 8.38861e+06); autoresizesSubviews = NO; layer = <CALayer: 0xaaaf810>>
    (id)*(&mapView+18) = 0x14346af0 <MKUserLocationView: 0x14346af0; frame = (1.34202e+06 3.24204e+06; 23 23); layer = <MKUserLocationLayer: 0x1433b8f0>> accuracy:-1.000000 +37.78583400, -122.40641700
    (id)*(&mapView+19) = 0xbfffda58 [no Objective-C description available]
[A] (id)*(&mapView+20) = 0x00411f90 [no Objective-C description available]
    (id)*(&mapView+21) = 0x09e55670 <MKMapView: 0x9e55670; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = TM+BM; layer = <CALayer: 0x9e55720>>
    (id)*(&mapView+22) = 0x0046f3e3 [no Objective-C description available]
    (id)*(&mapView+23) = 0x0aab0020 <MKAnnotationContainerView: 0xaab0020; frame = (0 0; 8.38861e+06 8.38861e+06); autoresizesSubviews = NO; layer = <CALayer: 0xaaaf810>>
    (id)*(&mapView+24) = 0x14346af0 <MKUserLocationView: 0x14346af0; frame = (1.34202e+06 3.24204e+06; 23 23); layer = <MKUserLocationLayer: 0x1433b8f0>> accuracy:-1.000000 +37.78583400, -122.40641700
    (id)*(&mapView+25) = 0x0aab0020 <MKAnnotationContainerView: 0xaab0020; frame = (0 0; 8.38861e+06 8.38861e+06); autoresizesSubviews = NO; layer = <CALayer: 0xaaaf810>>
    (id)*(&mapView+26) = 0x00000054 [no Objective-C description available]
    (id)*(&mapView+27) = 0x00000054 [no Objective-C description available]
    (id)*(&mapView+28) = 0x003fed75 [no Objective-C description available]
    (id)*(&mapView+29) = 0x09e55670 <MKMapView: 0x9e55670; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = TM+BM; layer = <CALayer: 0x9e55720>>
    (id)*(&mapView+30) = 0x49a3d250 [no Objective-C description available]
    (id)*(&mapView+31) = 0xbfffdab8 [no Objective-C description available]
[B] (id)*(&mapView+32) = 0x003fef87 [no Objective-C description available]
    (id)*(&mapView+33) = 0x0aab0020 <MKAnnotationContainerView: 0xaab0020; frame = (0 0; 8.38861e+06 8.38861e+06); autoresizesSubviews = NO; layer = <CALayer: 0xaaaf810>>
    (id)*(&mapView+34) = 0x0046ddfb [no Objective-C description available]
    (id)*(&mapView+35) = 0x00000001 [no Objective-C description available]
    (id)*(&mapView+36) = 0x00000001 [no Objective-C description available]
    (id)*(&mapView+37) = 0x00000001 [no Objective-C description available]
    (id)*(&mapView+38) = 0x433f8000 [no Objective-C description available]
    (id)*(&mapView+39) = 0xbfffdab8 [no Objective-C description available]
    (id)*(&mapView+40) = 0x015c85b4 [no Objective-C description available]
    (id)*(&mapView+41) = 0xbfffdaa0 [no Objective-C description available]
    (id)*(&mapView+42) = 0x49a3d250 [no Objective-C description available]
    (id)*(&mapView+43) = 0x4a45e070 [no Objective-C description available]
    (id)*(&mapView+44) = 0x00000000 <nil>
    (id)*(&mapView+45) = 0x0000000c [no Objective-C description available]
    (id)*(&mapView+46) = 0x00000054 [no Objective-C description available]
    (id)*(&mapView+47) = 0x41300000 [no Objective-C description available]
    (id)*(&mapView+48) = 0x43dc0000 [no Objective-C description available]
    (id)*(&mapView+49) = 0x41c00000 [no Objective-C description available]
    (id)*(&mapView+50) = 0x41300000 [no Objective-C description available]
    (id)*(&mapView+51) = 0x00000000 <nil>
    (id)*(&mapView+52) = 0x007c47dd [no Objective-C description available]
    (id)*(&mapView+53) = 0x0aaab070 <UITapGestureRecognizer: 0xaaab070; state = Ended; delaysTouchesEnded = NO; view = <UIView 0xaa93f00>; target= <(action=handleTap:, target=<MKMapView 0x9e55670>)>; must-fail = {
            <MKVariableDelayTapRecognizer: 0xaaad260; baseClass = UITapGestureRecognizer; state = Failed; view = <UIView 0xaa93f00>; target= <(action=handleDoubleTap:, target=<MKMapGestureController 0xaaadbe0>)>; numberOfTapsRequired = 2>
        }>
    (id)*(&mapView+54) = 0x00000004 [no Objective-C description available]
    (id)*(&mapView+55) = 0xbfffdb08 [no Objective-C description available]
[C] (id)*(&mapView+56) = 0x007c485a [no Objective-C description available]
    (id)*(&mapView+57) = 0x09e55670 <MKMapView: 0x9e55670; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = TM+BM; layer = <CALayer: 0x9e55720>>
    (id)*(&mapView+58) = 0x0046db75 [no Objective-C description available]
    (id)*(&mapView+59) = 0x132e7ce0 [no Objective-C description available]
    (id)*(&mapView+60) = 0x007c47dd [no Objective-C description available]

I added markers [A], [B] and [C] in rows where address is equal to address in callstack...

UPDATE 3:

Using this code I can determine if user tapped on my callout or not. I know I should not use this code, but it is just for experiment :)

if ([(id)*(&mapView+53) isKindOfClass:[UIGestureRecognizer class]])
{
    CGPoint point = [(id)*(&mapView+53) locationInView:callout];
    if (CGRectContainsPoint(callout.bounds, point))
    {
        NSLog(@"Inside the callout");
    }
    else
    {
        NSLog(@"Outside the callout");
    }
}

// I have a problem not related to this question 
// with callout right not, it closes after tap on it... 
k06a
  • 17,755
  • 10
  • 70
  • 110
  • Evil ABI hackage. Check out the ABI docs and do a lot of obscure pointer arithmetic. Not easy, but possible. –  Jul 03 '13 at 21:01
  • 1
    And it'll all fall apart in the face of the optimizer, too, where tail call and stack/register re-use is rife. – bbum Jul 03 '13 at 21:07
  • Closely related: [How to find out who called a method?](http://stackoverflow.com/q/1793999) – jscs Jul 03 '13 at 22:13
  • It's a bit of a shocker to find out that Objective-C isn't as message-oriented as it should be. But then again, if you sent the caller in through for every method it would probably start to devolve into reactive programming after a while. – CodaFi Jul 03 '13 at 23:00
  • 1
    I think your code is generating interesting output purely by coincidence. Which is great for debugging code! It looks like you are effectively just dumping the descriptions of objects that happen to be on the stack. I'm a bit surprised that works at all given that the first argument (3rd argument, really) is in a register! – bbum Jul 07 '13 at 14:45
  • For debugging purposes, you can use `thread backtrace all` in LLDB to print all stack frames (and the arguments that were passed to them). However, I'm fairly certain that you cannot use that technique at runtime. – Richard J. Ross III Sep 11 '15 at 19:06

0 Answers0