美文网首页
LLDB学习总结

LLDB学习总结

作者: 樂亦leeyii | 来源:发表于2018-06-28 15:46 被阅读0次

    目录

    • 设置断点
    • help
    • expression
    • print & po
    • 流程控制
    • 创建断点
    • watchpoit
    • 总结

    LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展

    设置断点

    在代码框左侧可以设置断点,当程序执行到断点所在的位置是,程序会停止,这个时候我们可以对程序进行调试。

    help

    在调试框内我们输入help命令,可以查看可以使用的命令及其简单的描述。

    如果希望看到某个命令的用法,可以在调试器内输入help 命令brankpoint为例。

    学会使用help命令,可以给我们在调试的过程中提供很多帮助。

    expression

    LLDB的命令遵循唯一匹配原则:假如根据前n个字母已经能唯一匹配到某个命令,则只写前n个字母等效于写下完整的命令。expressione表示相同的命令。

    如果希望修改某个值,可以使用expressione执行语句。在程序运行的中,如果使用e命令改变了某个变量的值,那么在实际运行过程中这个变量也会被修改。(仅在OC中有效,在swift中修改变量的值只在调试期间生效,当继续运行程序时,变量的值实际还是原来的值。)

    使用e声明变量时,使用$符号开始作为变量的第一个字符。

    expression命令的说有有这样一句话

    Important Note: Because this command takes 'raw' input, if you use any
    command options you must use ' -- ' between the end of the command options
    and the beginning of the raw input.

    在使用这个命令的时候需要使用--将实际 command options 和 实际的表达式分开以免造成歧义。

    print & po

    p

    平时使用中这是我们使用最多的两个命令.

    print可是使用p代替,实际上它只是expression -- 的别名。

    (lldb) e -- self.view
    (UIView?) $R0 = 0x00007fa1e2407000 {
      UIKit.UIResponder = {
        ObjectiveC.NSObject = {}
      }
    }
    (lldb) p self.view
    (UIView?) $R1 = 0x00007fa1e2407000 {
      UIKit.UIResponder = {
        ObjectiveC.NSObject = {}
      }
    }
    

    上面两个代码效果完全相同。

    在swift中如果使用let声明一个变量,使用lldb不能打印这个变量,如果你试图打印这个变量,将会得到下面的提示,因为编译器认为你不会再改变这个变量,所以即使修改optimization level 为 NONE也不能打印,如果你希望打印这个变量可以将这个变量用var声明。

    error: <EXPR>:3:1: error: use of unresolved identifier 'even1'
    even1
    ^~~~~
    

    po

    在OC和swift中所有的对象都是用指针代表的(除了某些特殊的对象,这里不做讨论),使用p打印出来的都是对象的指针,而不是对象的本身,如果我们想要打印对象,可以使用po(它实际上是expression -O --的别名)。po打印的内容在OC和swift中是有区别的。

    在OC中这样打印出来的是当前对象的description方法的返回值,如果没有实现回到父类中寻找,知道找到NSObject中,但是-[NSObject description]返回实际上也是对象的指针,和使用p并没有区别,所有对自定义的类,我们可以实现description方法来方便我们调试。

    在swift中,对遵守CustomDebugStringConvertible协议的类或结构体,使用po可以自定义打印内容。

    流程控制

    当程序到达断点的时候程序就会暂停,在调试条上面会出现4个可以控制流程的按钮

    1. continue 按钮,继续执行直到下一个断点,在LLDB中使用process continue,continue,c都能有相同的作用。
    2. step over 按钮, 会以黑盒的方式执行一行代码。如果所在这行代码是一个函数调用,那么就不会跳进这个函数,而是会执行这个函数,然后继续。LLDB 则可以使用 thread step-overnext,或者 n 命令。
    3. step in 按钮, 如果当前行是函数,则会进入函数内部,如果不是,则和step over作用相同,LLDB 则可以使用 thread step instep,或者 s 命令。
    4. step out 按钮,如果你曾经不小心跳进一个函数,但实际上你想跳过它,常见的反应是重复的运行 n 直到函数返回。其实这种情况,step out 按钮是你的救世主。它会继续执行到下一个返回语句 (直到一个堆栈帧结束) 然后再次停止。

    Thread Return

    调试时,还有一个很棒的函数可以用来控制程序流程:thread return 。它有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,然后立刻执行返回命令,跳出当前栈帧。这意味这函数剩余的部分不会被执行。这会给 ARC 的引用计数造成一些问题,或者会使函数内的清理部分失效。但是在函数的开头执行这个命令,是个非常好的隔离这个函数,伪造返回值的方式 。

    创建断点

    断点是一个非常强大的功能,在XCcode左侧有一个管理断点的面板,在这里可以看到所有的断点,并且可以管理,编辑和为断点添加行为。

    1529650655865.jpg

    编辑断点

    选中断点右键点击断点,出现下面断点

    1. condition:指定当满足条件时断点才会生效

    来看一个例子,在Condition中设置一个 i == 5

    代码如下

    override func viewDidLoad() {
        super.viewDidLoad()
        var i = 5
        // 在这里设置断点 
    }
    

    这个时候代码执行到这里时会暂停,如果修改代码var i = 6则断点不会停下。

    2. Ignore:忽略前N次

    上面断点设置Ignore为3,在控制台中会打印

    0
    1
    2
    (lldb) 
    

    然后程序暂停。

    3.Action

    上面的例子中,你或许想知道每一次到达断点的时候 i 的值。我们可以使用 p i 作为断点行为。这样每次到达断点的时候,都会自动运行这个命令。

    20180622151948.png

    4.赋值后继续运行

    看编辑断点弹出窗口的底部,你还会看到一个选项: "Automatically continue after evaluation actions." 。它仅仅是一个选择框,但是却很强大。选中它,调试器会运行你所有的命令,然后继续运行。看起来就像没有执行任何断点一样 (除非断点太多,运行需要一段时间,拖慢了你的程序)。

    watchpoit

    使用lldb也可以实现变量的监听。当我们关心某个类实例变量何时被修改,如果使用属性修改实例变量的值时,我们可以在setter方法中打断点或者直接在属性上面打上断点,都能够监听变量改变,但是有时候直接通过修改实例变量修改,不会调用setter方法。

    那么如何监听这个实例变量被改变了呢,我们可以通过监视这个实例变量的地址的写入。

    下面示例代码:

    class Person {
        
        var name: String!
        
    }
    

    如果希望监听Person实例变量name的改变

        let person = Person()
        // 在这里打上断点
        person.name = "john"
        
        person.name = "toms"
    

    控制台

    (lldb) watchpoint set variable -s 8 -- person.name
    Watchpoint created: Watchpoint 1: addr = 0x6000004468b0 size = 8 state = enabled type = w
        declare @ '/Users/blade/Desktop/LLDBTest/LLDBTest/ViewController.swift:26'
        watchpoint spec = 'person.name'
        new value: ""
    

    person.name的值被修改的时候会程序会暂停,但是我在试验的遇到一个问题,第一次修改的时候new value总是空的,我也不知道是为什么。

    // 监听属性修改时,控制台打印
    Watchpoint 1 hit:
    old value: ""
    new value: ""
    
    Watchpoint 1 hit:
    old value: ""
    new value: "toms"
    

    注意在OC中需要通过watchpoint set variable -s 8 -- person->_name这种方式去监听变量的变化。

    总结

    lldb是非常强大的,如果掌握的这些方法,能够极大提高解决bug的效率。

    引用

    lldb error: variable not available

    与调试器共舞 - LLDB 的华尔兹

    相关文章

      网友评论

          本文标题:LLDB学习总结

          本文链接:https://www.haomeiwen.com/subject/qwggyftx.html