• LLDB 调试


    LLDB是 XCode 内置的为我们开发者提供的调试工具。
    LLDB 可以提供的服务:
    • 允许你在程序的特定时刻暂停它;
    • 允许你查看变量的值;
    • 执行自定的指令;
    • 按照你所认为合适的步骤来操作程序的进展。

    语法

    <command> [<subcommond>]
    唯一匹配原则:假如根据前n个字母已经能唯一匹配到某个命令,则只写前n个字母等效于写下完整的命令。
    每一个 LLDB 命令都包含着 0 个到多个子命令,并且可能具有一个到多个可选参数。
    --:表示命令(或子命令)的结束,以及输入的开始。
    express -h +17,让人很困惑,到底是以 -h 为标识,仅仅执行 +17,还是计算 17 和 h 的差值。所以用 -- 表示标识的结束和输入的开始。如果想要 -h 作为标识,就用 express -h -- +17。如果是要计算他们的差值,就使用 express -- -h +17。因为一般不使用标识的情况比较多,所以 express -- 就有了一个简写方式,那就是 print。
    输入 help print 可以看到。
    []:表示可选。

    常用命令

    help

    列举出所有的命令,可以通过 help <command> 来了解更多细节。
    例如:help thread help print 等。

    apropos

    有的时候,可能并不能完全记得某个命令,只记得某个关键词。就可以使用 apropos 搜索到相关命令信息。
    例如:(lldb) apropos stop-hook

    print

    • 打印值
    根据唯一匹配原则,你可以使用 prin,pri,甚至 p。但是不能使用 pr,因为 LLDB 不能消除和 process 的歧义(幸运的是 p 并没有歧义)。
    • 打印对象
    一般打印对象,会出现 $0 = 0x00007fdb9b71b3e0, 但是我们想看到的是对象的 description 方法的结果。
    所以使用 -o,告诉 expression 命令以 对象(object)的方式来打印结果。
    expression -o -- 有个别名,就是 po (print object)的缩写。
     
    po [[UIWindow keyWindow] recursiveDescription] 来检查层次结构。
    它可以以文本形式打印出完整的视图层次结构
    可以用 po [[[UIWindow keyWindow] rootViewController] _printHierarchy] 来检查视图控制器。
    • 打印变量
    可以给 print 指定不同的打印格式。都是以 print/<fmt> 或者 p/<fmt> 格式书写。
    (lldb) p 16 -> 16
    (lldb) p/x 16 //十六进制 -> 0x10
    (lldb) p/t 16 //二进制 -> 0b00000000000000000000000000010000
    (lldb) p/t (char)16 ->0b00010000
    p/c 打印字符
    p/s 打印字符串(以'' 结尾的字符串)

    expression

    执行指定表达式,并将结果打印出来。常用于改变调试器中的值,即改变程序中的值。
    完整语法:
    express <cmd -options> -- <expr>
    <cmd -options>:命令选项,使用默认即可;
    <expr >:要执行的表达式
    调试过程中,我们经常用到假设某个变量是某个值,就不需要代码写死了;只需打个断点,执行如下即可,非常方便。
    例:expr a = 10
     
    在 lldb 中声明一个对象,为了下文中可以使用声明的变量,变量必须以 美元符开头。
    (lldb) e int $a = 2
    (lldb) p $a * 19 -> 38
     
    (lldb) e NAArray *$array = @[@"Sturday", @"Sunday"]
    (lldb) p [$array count] ->2
    (lldb) po [[$array objectAtIndex:0] uppercaseString] -> SATURDAY
    注:lldb 无法确定返回的类型

    thread backtrace & bt

    打印线程堆栈信息
    完整语法:
    thread backtrace [-c <count>] [-s <frame-index>] [-e <boolean>]
    -c:设置打印堆栈的帧数
    -s:设置从哪个帧开始打印
    -e:是否显示额外的回溯
    实际上这些命令选项一般不需要使用。
    当发生 crash 时,可以使用
    (lldb) thread backtrace //查看栈帧信息
    该命令还有一个别名:bt
    bt all:打印所有的 thread 堆栈
     

    thread return

    thread return [<expr>]
    该命令可以接受一个表达式,调用命令后直接从当前的 frame 返回表达式的值。
    //它有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,然后立刻执行返回命令,跳出当前栈帧。这意味这函数剩余的部分不会被执行。这会给 ARC 的引用计数造成一些问题,或者会使函数内的清理部分失效。但是在函数的开头执行这个命令,是个非常好的隔离这个函数,伪造返回值的方式 。
     
    thread 还有一些不常用的命令
    thread jump:直接让程序跳到某一行。ARC 下编译器实际插入了不少 retain,release命令,跳过一些代码不执行很可能会造成对象内存混乱发生 crash。
    thread list:列出所有的线程。
    thread select:选择某个线程。
    thread until:传入一个 line 参数,让程序执行到这行的时候暂停。
    thread info:输出当前线程的信息。

    watchpoint

    观察变量或者属性

    这是一个非常有用的东西,我们经常遇到,某一个变量,不知道什么时候值被改掉了,就可以使用这个东西去定位:
    (lldb) watchpoint set variable self->_string
    不能使用点语法

    watchpoint set expression (观察地址)

    如果想观察某个地址,可以使用 watchpoint set expression
    例如:先拿到 _model 的地址,然后对地址设置一个 watchpoint
    (lldb) p &_model
    (Modek **) $3 = 0x00007fe0dbf23280
    (lldb) watchpoint set expression 0x00007fe0dbf23280
    Watchpoint created: Watchpoint 1: addr = 0x7fe0dbf23280 size = 8 state = enabled type = w
        new value: 0
     
    watchpoint command
    跟 breakpoint 类似,watchpoint 也可以添加命令
    watchpoint command add (添加观察点)
    例如:
    (lldb) watchpoint set variable xxx
    Watchpoint created: Watchpoint 1: addr = 0x7fe4e1444760 size = 8 state = enabled type = w
        watchpoint spec = '_string'
        new value: 0x0000000000000000
    watchpoint 的 id 是1.
    watchpoint command add -o 'bt' 1
    在 watchpoint 停下来时,打印了它的线程信息
     
    也可以添加多条命令:
    (lldb) watchpoint command add 1
    Enter your debugger command(s).  Type 'DONE' to end.
    > bt
    > continue
    > DONE
     
    watchpoint command list (某观察点所有命令)
    watchpoint command list 1
    列出某个 watchpoint 的所有 command
     
    watchpoint command delete (观察点删除)
    watchpoint command delete 1
    删除某个 watchpoint 所有的 command
     
    watchpoint list (观察点列表)
    查看当前所有的 watchpoint,使用 watchpoint list
     
     
    watchpoint disable (观察点失效)
    让某个 watchpoint 失效
     
    watchpoint enable (观察点生效)
    使某个 watchpoint 生效
     
     
    watchpoint delete index
    删除某个 watchpoint。
    不指定 index,则删除所有的 watchpoint。
     

    target modules & image:查找地址对应的文件位置

    LLDB 给 target modules 取了个别名 image。
     
    image lookup -address
    查找这个地址具体对应的文件位置。
    比如:
    TLLDB[25086:246169] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 1 beyond bounds for empty NSArray'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x000000010accde65 __exceptionPreprocess + 165
        1   libobjc.A.dylib                     0x000000010a746deb objc_exception_throw + 48
        2   CoreFoundation                      0x000000010ac7c395 -[__NSArray0 objectAtIndex:] + 101
        3   TLLDB                               0x000000010a1c3e36 -[ViewController viewDidLoad] + 86
        4   UIKit                               0x000000010b210f98 -[UIViewController loadViewIfRequired] + 1198
        5   UIKit                               0x000000010b2112e7 -[UIViewController view] + 27
    我们可以看到数组越界了,但是 objectAtIndex: 的代码在哪呢?
    使用 image lookup
    (lldb) image lookup -a 0x000000010a1c3e36
          Address: TLLDB[0x0000000100000e36] (TLLDB.__TEXT.__text + 246)
          Summary: TLLDB`-[ViewController viewDidLoad] + 86 at ViewController.m:32
     
    image lookup -name
    查找一个方法 或者 符号的信息
    例如: 第三方 SDK 有一个 Dictionary 的 catagory,和我们自己的 catagory 冲突了,但是不知道在哪个 .a 里面。
    使用 image lookup -n dictionaryWithXMLString: 即可。
     
    image lookup -type
    查看一个类型
    image lookup -t Model
    所有的属性,实例变量都会打出来
     
    target stop-hook
    使用 LLDB debug,大多数时候需要让程序 stop。该命令可以在每次 stop 的时候去执行一些命令。
     
    target stop-hook add & display
    例如:每次程序 stop 时,都用命令打印当前 frame 的所有变量。可以添加一个 stop-hook
    (lldb) target stop-hook add -o "frame variable"
    -o:--one-liner,表示添加一条命令。
     
    LLDB 提供了一个更简便的命令:display。下面这两条等同
    (lldb) target stop-hook add -o "p self.view"
    (lldb) display self.view
     
    target stop-hook list
    可以查看所有的 stop-hook
     
    target stop-hook delete & undisplay
    删除某个 stop-hook
    (lldb) target stop-hook delete index
    (lldb) undisplay index
     
    target stop-hook disable/enable
    使某个 stop-hook 失效/生效。
     
     
     
     
    参考文章
  • 相关阅读:
    AcWing 276. I-区域
    学习笔记:可持久化线段树(主席树):静态 + 动态
    NOIP2016提高组 天天爱跑步
    AcWing 195. 骑士精神
    标准文档流
    css 盒模型
    css 继承性和层叠性
    css 选择器
    css 引入方式
    html body中的标签2
  • 原文地址:https://www.cnblogs.com/lion-witcher/p/10405205.html
Copyright © 2020-2023  润新知