Xcode 常用 LLDB 指令

作者: CoderHG | 来源:发表于2018-05-10 20:43 被阅读166次

    LLDBXcode 中自带的一个调试工具,在开发的过程中使用好了这个调试工具,不仅是能力的一种提升,更是一种装逼的 神器

    一、如何进入 LLDB

    通常当程序 crash 或者有断点的时候,会自动的变成 LLDB 模式。也可以手动 处理,直接点击这里:


    image.png

    也会变成 LLDB 模式。最终的效果是这样的:


    image.png

    二、使用 LLDB

    2.1 expr 指令

    这个指令的意思,能实时的执行代码中的代码逻辑。就像下面这样的:

    image.png

    当点击下一步执行的时候,NSLog 打印的值是 CoderHG 而不是 Coder。这个功能想想都感觉挺不错的。

    由于最近在学习 ShellPython ,于是刚刚这样脑补了一下:

    image.png

    这样是行不通的,难怪大家都说 ShellPython 很强大。[偷笑5分钟,犯困一小时]

    2.2 call

    这个指令与 expr 类似,调用一行代码,形如这样的:

    call self.view.backgroundColor = [UIColor redColor];

    image.png

    2.3 打印

    其实关于打印,应该所有的小伙伴都知道的。接着上面的步骤,做如下的操作:


    image.png

    在 LLDB 中有两个常见的打印指令 ppo

    • 1、p 通常用于打印基本数据类型的值。这个指令会默认生出一个临时变量,如$1,学习过 Shell 的小伙伴看到这个应该很激动。
    • 2、po 打印变量的内容,如果是对象,其打印的内容由 -debugDescription 决定。
    image.png

    2.4 操作内存

    对内存的操作,无非就是读写操作。
    修改内存中的值:

    memory write 内存地址 数值

    如:memory write 0x7ffee685dba8 25

    读取内存操作:

    memory read/数量 _ 格式 _ 字节数 内存地址

    或者

    x/数量 _ 格式 _ 字节数 内存地址

    2.4.1 格式
    • x :代表16进制
    • f :代表浮点数
    • d :代表10进制
    2.4.2 字节大小
    • b :byte 代表1个字节
    • h :half word 代表2个字节
    • w :word 代表4个字节
    • g :giant word 代表8个字节

    如:

    memory read/1wx 0x7ffee14a5ba8
    memory read/1wd 0x7ffee14a5ba8

    寓意是:读取 0x7ffee14a5ba8 中 4 个字节的内容。
    示例如下:

    image.png

    2.5 bt

    bt 返回所有的调用栈, 形如:

    (lldb) bt
    * thread #1, queue = 'com.apple.main-thread', stop reason = step over
      * frame #0: 0x000000010758b6fd LLDBDev`-[ViewController viewDidLoad](self=0x00007fedad7057e0, _cmd="viewDidLoad") at ViewController.m:27
      **中间被我干掉了很多。**
        frame #34: 0x000000010758b79f LLDBDev`main(argc=1, argv=0x00007ffee8674108) at main.m:14
        frame #35: 0x000000010c2d1d81 libdyld.dylib`start + 1
        frame #36: 0x000000010c2d1d81 libdyld.dylib`start + 1
    

    这个指令很强大,现在的 Xcode 在这里都显示不全了:


    image.png

    所以只能借助 bt 指令。

    三、实战

    没有实战的纸上谈兵,都是耍流氓。
    在开始之前,先定义一个 Class,代码如下所示:

    #import <Foundation/Foundation.h>
    
    @interface HGObject : NSObject
    
    /** 年龄 */
    @property (nonatomic, assign) NSInteger age;
    /** 身高 */
    @property (nonatomic, assign) NSInteger height;
    
    @end
    
    
    
    #import "HGObject.h"
    
    @implementation HGObject
    
    @end
    

    很简单的一个Class。

    3.1 查看一个对象的 isa 指针

    大家都说一个instance 对象中的 isa 的值就是当前 instance 对象的 class 对象的值,接下来求证一下。先写一段简单的代码:

    Class cls = NSClassFromString(@"HGObject");
    id obj = [[cls alloc] init];
    NSLog(@"%@, %@", cls, obj);
    
    image.png

    运行代码发现:

    • 1、cls 没有显示具体的地址值。
    • 2、在 obj 中也根本没有看到 isa 这个成员变量。

    看不到任何的地址显示,所以只能是借助 LLDB 调试工具,这里既是是使用简单的 p 或者 po指令都是不可以的。需要借助上面说的 操作内存 的指令。

    image.png

    轻松搞定,上图中是不是就说明了一个 Class 对象的 instance 对象的 isa 的值就是其 class 对象本身的值呢?是的,本来就是这样的。

    3.2 对象中的地址查看

    简单的实现如下代码:

    HGObject* obj = [[HGObject alloc] init];
    obj.age = 18;
    obj.height = 2;
    
    NSLog(@"%@", obj);
    

    在 NSLog 处打一个断点,运行代码,打开内存查看视图:


    image.png

    刚打开是这样的:


    image.png

    将 obj 的地址写入,再看下面这张图:


    image.png

    看到上面的内存图,发现一个规律,请看下图:


    image.png

    上图中的内存分布,如红框框所示,分别是 isa,_age 与 _height。为了验证其正确性,可以修改一下其中的值,看一下效果:


    image.png

    上图中的逻辑大概为:查找 _age 与 _height 对应的地址,然后修改其地址的值,然后刷新看内存视图。

    四、说在最后的话

    记录这些技巧,一方面是因为这些技巧往往都被我们所忽视,记录一下说明自己了解过。但是一旦熟练使用这些技巧,往往在开发中能减少大量的调试时间。

    其实,为了装逼才是最重要的。

    相关文章

      网友评论

        本文标题:Xcode 常用 LLDB 指令

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