37

I have a breakpoint that looks like this

-[UITableViewCell setSelected:]

and it works, but I cannot figure out how to get the value that is being passed in.

I have tried -[UITableViewCell setSelected:(BOOL)what] and -[UITableViewCell setSelected:what] which do not work at all.

How can I access the parameters?

If this doesn't work, I'll have to make a DebugUITableViewCell just to see what's going on, which is a hassle and touches a lot of code.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 1
    I'm not brave enough to post this a real answer as I"m just speculating, but I believe want is just not available to the debugger. You don't get the symbols for UIKit so the debugger has no idea about what the name of the argument is to that method. the runtime might be able to figure out its type, but its not the same as having the real symbol information. Your subclass trick works I guess because you are also providing that symbol info to the debugger. – D.C. Mar 20 '13 at 00:29
  • I arrived at this question for the exact same method — without even including the method name in the search query. Table views truly are a mystery, and even more so 5 years later! – Constantino Tsarouhas Sep 19 '18 at 13:02

7 Answers7

35

If you debug your code on the device the parameters when you hit your breakpoint will consistently be in registers r0, r1, and r2. If you use po $r0 you'll see the object receiving setSelected. If you use po $r1 you'll get "no Objective-C description available" because that's the selector. Inspect $r2 to see if selected is being set to YES or NO. It's a similar story on i386, but I can't remember off hand which registers are used.

Aaron Golden
  • 7,092
  • 1
  • 25
  • 31
  • I know this was a well-used trick with gdb, but I believe it will not work consistently in lldb. – D.C. Mar 20 '13 at 01:36
  • 1
    @darren I tested this with lldb before posting my answer, but what makes you think it wouldn't work? – Aaron Golden Mar 20 '13 at 01:42
  • 17
    It will work fine with lldb. In fact, it's even better in lldb because (for architectures that pass arguments in registers, like arm and x86_64) `$arg0`, `$arg1` etc are provided which alias to the correct register for that architecture. – Jason Molenda Mar 20 '13 at 02:25
  • Incidentally, for i386 you need to read stack memory based on the stack pointer (if you're on the first instruction of the function/method) to find the arguments. – Jason Molenda Mar 20 '13 at 02:26
  • Cool. I remember trying this out when LLDB first came out and thought it was not working as i expected. Thanks for confirming it does work as expected. – D.C. Mar 20 '13 at 02:40
  • @JasonMolenda I thought on i386 some arguments are passed via register, with the rest on the stack? – nielsbot Mar 20 '13 at 02:56
  • The return value from the function is passed in eax IIRC but otherwise all argument passing is on the stack. If a function is only called from within a single dylib it is possible to use a non-standard ABI that passes args in regs -- I think there may even be a command line option to clang to do this, or at least there was one for gcc in the distant past, but it would be an alternate ABI and any callers would need to know about it. – Jason Molenda Mar 22 '13 at 02:54
  • 13
    In lldb access the arguments starting with $arg1. For a method call the first user argument is $arg3; So if the first method argument is a NSString just `po $arg3` to display it. – zaph May 10 '13 at 16:23
  • 4
    Tried to log a `CGPoint` argument but `p (CGPoint)$arg3` doesn't work. – Ortwin Gentz Oct 08 '13 at 23:38
  • 1
    I also could not get `po $arg0` to work in lldb. Tried both x86_64 and on arm64. – stigi Jan 28 '14 at 10:09
  • po $r2 and po $arg3 is good for the first parameter. But how to get the second parameter, the third parameter – vietstone Mar 11 '14 at 06:41
  • While debugging in the Xcode 6 iOS Simulator, `$arg1`..etc., were not recognised. But this did work: [Accessing parameters on Intel 32-bit](https://developer.apple.com/library/ios/technotes/tn2239/_index.html#//apple_ref/doc/uid/DTS40010638-CH1-TABLE2). For example, with a break at `-[CALayer setBackgroundColor:]`, I used a log message action: `[@(NSString*)[((CALayer*)(*(int*)($esp+4))).delegate description]@ setBackgroundColor: @(NSString*)[(id)*(int*)($esp+12) description]@]` and autocontinue - very useful for a tricky problem I had. /cc @stigi @ortwingentz – t0rst Dec 04 '14 at 08:05
  • 1
    [Accessing parameters on ARM](https://developer.apple.com/library/ios/technotes/tn2239/_index.html#//apple_ref/doc/uid/DTS40010638-CH1-TABLE1). [Accessing parameters on Intel 32-bit](https://developer.apple.com/library/ios/technotes/tn2239/_index.html#//apple_ref/doc/uid/DTS40010638-CH1-TABLE2). – t0rst Dec 04 '14 at 08:18
  • @t0rst, What about accessing them in `lldb`? – Iulian Onofrei Jan 12 '18 at 09:41
18

In LLDB on Simulator use

p $arg3

for the first parameter.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
6

You could replace -[UITableViewCell setSelected:] with your own implementation for debugging purposes. Below, UITableViewCellSetSelected will be called instead of UIKit's method.

static void (*__originalUITableViewCellSetSelected)( UITableViewCell *, SEL, BOOL ) ;
static void UITableViewCellSetSelected( UITableViewCell * self, SEL _cmd, BOOL b )
{
    // your code here... (or set a breakpoint here)
    NSLog(@"%@<%p> b=%s\n", [ self class ], self, b ? "YES" : "NO" ) ;

    (*__originalUITableViewCellSetSelected)( self, _cmd, b ) ; // call original implementation:
}

@implementation UITableViewCell (DebugIt)

+(void)load
{
    Method m = class_getInstanceMethod( [ self class ], @selector( setSelected: ) ) ;
    __originalUITableViewCellSetSelected = (void(*)(id, SEL, BOOL))method_getImplementation( m ) ;
    method_setImplementation( m, (IMP)UITableViewCellSetSelected ) ;
}

@end
nielsbot
  • 15,922
  • 4
  • 48
  • 73
3

For the methods without source code, the following works: Put a symbolic breakpoint so that the debugger stops at the first line of the method. Make sure the top stack frame is selected. Then:

In Objectice-C methods

  • po $arg1 prints self
  • po $arg3 prints the first argument, remaining arguments in $arg4, $arg5, etc.

In C functions the arguments start at $arg1

This works both on IOS device and simulator.

  • `$arg1` etc will only work for 64 bit simulators. For legacy x86 32bit ones that would translate to `x/x $esp4` , `x/x $esp+8` etc See https://stackoverflow.com/a/48734614/5329717 – Kamil.S Nov 10 '21 at 13:02
2

Based on -[UIApplication sendAction:toTarget:fromSender:forEvent:] symbol we can add symbolic breakpoint to check which sender has sent an action to which target.

We create symbolic breakpoint with:

  • symbol: -[UIApplication sendAction:toTarget:fromSender:forEvent:]
  • debugger command line actions:
    • po "Target"
    • po $arg4
    • po "Sender"
    • po $arg5

The output would be: "Target" <project.TargetViewController: 0x14ddb1470> "Sender" <UIButton: 0x14de86000; frame = (331 7; 49 30); opaque = NO; layer = <CALayer: 0x174237020>>

So as @Dan said, method parameters start with argument 3 (po $arg3).

0

you can use lldb command:

"image lookup -rn keyword"

keyword equals functions you wanna search, eg, show

then, you will look some output like follows,

Summary: ApplSlate`closure #2 (__C.UIBarButtonItem) -> () in ApplSlate.BaseTableViewController.showLoading(includeTabBar: Swift.Bool) -> () at BaseTableViewController.swift:98 Address: FullSlate[0x0000000100154a60] (FullSlate.__TEXT.__text + 1378752)

And you get the symbolic name is : closure #2 (__C.UIBarButtonItem) -> () in ApplSlate.BaseTableViewController.showLoading(includeTabBar: Swift.Bool) -> ()

knight2016
  • 539
  • 6
  • 12
0

Answer

Xcode's lldb get ObjC first parameter is: $arg3

->

  • lldb print first parameter value: po $arg3
    • enter image description here
  • Xcode add symbolic breakpoint condition: still use arg3
    • eg
      • Condition: (BOOL)($arg3 == NULL)
        • enter image description here

Related

  • rest parameter is: $arg4, $arg5, ...
  • $arg0 not exists
    • eg
      (lldb) po $arg0
      error: <user expression 3>:1:1: use of undeclared identifier '$arg0'
      $arg0
      ^
      
  • $arg1 is function type
    • - means Instance
      • eg
        (lldb) po $arg1
        _
        
    • + means Class
  • $arg2 is function pointer self, use SEL can parse to function name
    • eg
      (lldb) po $arg2
      8203662366
      
      (lldb) po (SEL)$arg2
      "stringByAppendingString:"
      
crifan
  • 12,947
  • 1
  • 71
  • 56
  • thanks. does this add new value that's not in the accepted answer? – Dan Rosenstark Jan 14 '22 at 17:56
  • I think yes, at least add SOME extra value for `Related` part of my answer, for other (newbie) like me before – crifan Jan 15 '22 at 01:51
  • Seems like more of a comment on an answer, but ok. Could you please fix the answer to use `Xcode` (the name of the IDE) instead of `XCode` (common mistake)? Thanks. – Dan Rosenstark Mar 22 '22 at 15:05