【问题标题】:How to step over objc_msgSend function in lldb?如何跳过 lldb 中的 objc_msgSend 函数?
【发布时间】:2016-12-28 11:13:13
【问题描述】:

在 Objective-c 中,函数 cal 被转换为 objc_msgSend。例如

[foo doSomething:@"keke"]

被翻译成

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

在 lldb 中调试时如何直接跳转到 foo.doSomething:

【问题讨论】:

    标签: objective-c lldb


    【解决方案1】:

    lldb 确实提供了可以控制步骤逻辑的线程计划。

    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
    

    创建一个 python 脚本,将其加载到 lldb。 运行thread step-scripted gotouser.GotoUser.
    任务完成。

    完整的源代码: https://github.com/Jichao/lldb-scripts/blob/master/gotouser.py

    lldb 内置版本: https://github.com/Jichao/lldb

    【讨论】:

      【解决方案2】:

      使用 Python 线程计划很聪明!但是您不必为 ObjC 消息执行此操作。 lldb 知道 objc_msgSend 和其他一些是 ObjC 消息的调度函数。因此,如果step in 以 objc_msgSend 结束,lldb 将从传入的对象/选择器对中找出方法实现,在那里设置断点,然后继续。

      例如:

      (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   
      

      因此,在这种情况下,该步骤在实际的消息接收者处停止。如果这不是您正在发生的事情,则很可能是某些事情正在欺骗 lldb 中执行对象/选择器-> 实现查找的部分。我必须更多地了解您的代码才能弄清楚为什么会这样。

      【讨论】:

      • 啊,是的,这是一个独立的问题。默认情况下,如果“步入”到达没有调试信息的函数,lldb 不会停止,而是会再次退出。 “step”命令有一个标志来控制这种行为:--step-in-avoids-no-debug 或简称-a。如果您将其设置为 false,那么无论它是否具有调试信息,该步骤都将在目标方法中停止。还有一个通用设置:target.process.thread.step-in-avoid-nodebug,您可以设置(使用settings set)命令来全局控制此行为,如果这更符合您的口味。
      猜你喜欢
      • 2016-01-15
      • 2015-08-08
      • 2013-02-24
      • 2020-12-07
      • 2017-08-07
      • 1970-01-01
      • 2013-03-03
      • 2016-11-05
      • 1970-01-01
      相关资源
      最近更新 更多