'How to step over objc_msgSend function in lldb?

In objective-c, function cal is translated to objc_msgSend. e.g.

[foo doSomething:@"keke"]

is translated to

objc_msgSend(foo, "doSomething:", @"keke")

How could I step directly to foo.doSomething: while debugging in lldb?



Solution 1:[1]

lldb does provide thread plan which could control the step logic.

class GotoUser:
    def __init__ (self, thread_plan, dict):
        self.start_time = time.time()
        self.thread_plan = thread_plan
        target = self.thread_plan.GetThread().GetProcess().GetTarget();
        module = target.GetModuleAtIndex(0)
        sbaddr = lldb.SBAddress(module.GetObjectFileHeaderAddress())
        self.start_address = sbaddr.GetLoadAddress(target)
        module = target.GetModuleAtIndex(1)
        sbaddr = lldb.SBAddress(module.GetObjectFileHeaderAddress())
        self.end_address = sbaddr.GetLoadAddress(target)
        print "start addr: ", hex(self.start_address), " end addr: ", hex(self.end_address)

    def explains_stop (self, event):
        if self.thread_plan.GetThread().GetStopReason()== lldb.eStopReasonTrace:
            return True
        else:
            return False

    def should_stop (self, event):
        cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
        if cur_pc >= self.start_address and cur_pc <= self.end_address:
            self.thread_plan.SetPlanComplete(True)
            print 'time used ', (time.time() - self.start_time)
            return True
        else:
            return False

    def should_step (self):
        return True

create a python script, load it to lldb. run thread step-scripted gotouser.GotoUser.
mission completed.

full source code: https://github.com/Jichao/lldb-scripts/blob/master/gotouser.py

version built into lldb: https://github.com/Jichao/lldb

Solution 2:[2]

Using the Python thread plan is clever! But you should not have to do this for ObjC messages. lldb knows that objc_msgSend & a few others are the dispatch functions for ObjC messages. So if a step in ends up at objc_msgSend, lldb will figure out the method implementation from the object/selector pair passed in, set a breakpoint there, and continue.

For instance:

(lldb) run
Process 55502 launched: '/private/tmp/trivial' (x86_64)
Process 55502 stopped
* thread #1: tid = 0x32619ba, function: main , stop reason = breakpoint 1.1
    frame #0: 0x0000000100000f28 trivial`main at trivial.m:18
   15   main()
   16   {
   17     Trivial *my_foo = [[Trivial alloc] init];
-> 18     [my_foo doSomething];
   19     return 0;
   20   }
(lldb) s
Process 55502 stopped
* thread #1: tid = 0x32619ba, function: -[Trivial doSomething] , stop reason = step in
    frame #0: 0x0000000100000ed7 trivial`-[Trivial doSomething] at trivial.m:10
   7    @implementation Trivial
   8    - (void) doSomething
   9    {
-> 10     NSLog(@"%@ called doSomething.", self);
   11   }
   12   @end
   13   

So the step in stopped at the actual message receiver in this case. If that is not what is happening for you, most likely something is fooling the part of lldb that does the object/selector -> implementation lookup. I'd have to know more about your code to figure out why that might be.

Solution 3:[3]

How could I step directly to foo.doSomething: while debugging in lldb?

seems: No possbile

  • Workaround: add related breakpoint

    • your here: -[foo doSomething:]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jichao
Solution 2 Jim Ingham
Solution 3 crifan