iOS 常用的lldb命令

作者: boundlessocean | 来源:发表于2016-11-25 14:42 被阅读226次
    lldb.jpg

    一、expression

    expression命令的作用是执行一个表达式,并将表达式返回的结果输出。expression的完整语法是这样的:

    expression <cmd-options> -- <expr>
    

    1.<cmd-options>:命令选项,一般情况下使用默认的即可,不需要特别标明。
    2.--: 命令选项结束符,表示所有的命令选项已经设置完毕,如果没有命令选项,--可以省略
    3.<expr>: 要执行的表达式
    说expression是LLDB里面最重要的命令都不为过。因为他能实现2个功能。

    • 执行某个表达式。
      我们在代码运行过程中,可以通过执行某个表达式来动态改变程序运行的轨迹。
      假如我们在运行过程中,突然想把self.view颜色改成红色,看看效果。我们不必写下代码,重新run,只需暂停程序,用expression改变颜色,再刷新一下界面,就能看到效果
    // 改变颜色
      (lldb) expression -- self.view.backgroundColor = [UIColor redColor]
      // 刷新界面
      (lldb) expression -- (void)[CATransaction flush]
    
    • 将返回值输出。
      也就是说我们可以通过expression来打印东西。
      假如我们想打印self.view:
    (lldb) expression -- self.view
        (UIView *) $1 = 0x00007fe322c18a10
    

    二、p & print & call

    1.print: 打印某个东西,可以是变量和表达式
    2.p: 可以看做是print的简写
    3.call: 调用某个方法。
    表面上看起来他们可能有不一样的地方,实际都是执行某个表达式(变量也当做表达式),将执行的结果输出到控制台上。所以你可以用p调用某个方法,也可以用call打印东西
    e.g: 下面代码效果相同:

    (lldb) expression -- self.view
    (UIView *) $5 = 0x00007fb2a40344a0
    (lldb) p self.view
    (UIView *) $6 = 0x00007fb2a40344a0
    (lldb) print self.view
    (UIView *) $7 = 0x00007fb2a40344a0
    (lldb) call self.view
    (UIView *) $8 = 0x00007fb2a40344a0
    (lldb) e self.view
    (UIView *) $9 = 0x00007fb2a40344a0
    

    三、po

    OC里所有的对象都是用指针表示的,所以一般打印的时候,打印出来的是对象的指针,而不是对象本身。如果我们想打印对象。我们需要使用命令选项:-O。为了更方便的使用,LLDB为expression -O --定义了一个别名:po

    (lldb) expression -- self.view
    (UIView *) $13 = 0x00007fb2a40344a0
    (lldb) expression -O -- self.view
    <UIView: 0x7fb2a40344a0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fb2a4018c80>>
    (lldb) po self.view
    <UIView: 0x7fb2a40344a0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fb2a4018c80>>
    

    四、thread(thread backtrace & bt)

    当发生crash的时候,我们可以使用thread backtrace查看堆栈调用

    (lldb) thread backtrace
    * thread #1: tid = 0xdd42, 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
        frame #0: 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11
      * frame #1: 0x000000010aa9f75e TLLDB`-[ViewController viewDidLoad](self=0x00007fa270e1f440, _cmd="viewDidLoad") + 174 at ViewController.m:23
        frame #2: 0x000000010ba67f98 UIKit`-[UIViewController loadViewIfRequired] + 1198
        frame #3: 0x000000010ba682e7 UIKit`-[UIViewController view] + 27
        frame #4: 0x000000010b93eab0 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 61
        frame #5: 0x000000010b93f199 UIKit`-[UIWindow _setHidden:forced:] + 282
        frame #6: 0x000000010b950c2e UIKit`-[UIWindow makeKeyAndVisible] + 42
    

    我们可以看到crash发生在-[ViewController viewDidLoad]中的第23行,只需检查这行代码是不是干了什么非法的事儿就可以了。
    LLDB还为backtrace专门定义了一个别名:bt,他的效果与thread backtrace相同,如果你不想写那么长一串字母,直接写下bt即可:

    (lldb) bt
    

    五、thread return

    Debug的时候,也许会因为各种原因,我们不想让代码执行某个方法,或者要直接返回一个想要的值。这时候就该thread return上场了。
    e.g: 我们有一个someMethod方法,默认情况下是返回YES。我们想要让他返回NO

    1122433-cf22e45902233a0c.png.jpeg
    (lldb) thread return NO
    

    六、c & n & s & finish

    用触摸板的孩子们可能会觉得点击这4个按钮比较费劲。其实LLDB命令也可以完成上面的操作,而且如果不输入命令,直接按Enter键,LLDB会自动执行上次的命令。按一下Enter就能达到我们想要的效果,有木有顿时感觉逼格满满的!!!
    我们来看看对应这4个按钮的LLDB命令:

    1122433-17ba978ac411af3d.png.jpeg

    1.c/ continue/ thread continue: 这三个命令效果都等同于上图中第一个按钮的。表示程序继续运行
    2.n/ next/ thread step-over: 这三个命令效果等同于上图第二个按钮。表示单步运行
    3.s/ step/ thread step-in: 这三个命令效果等同于上图第三个按钮。表示进入某个方法
    4.finish/ step-out: 这两个命令效果等同于第四个按钮。表示直接走完当前方法,返回到上层frame

    七、frame variable

    前面我们提到过很多次frame(帧)。可能有的朋友对frame这个概念还不太了解。随便打个断点

    1122433-4dce2f2ba17e3857.png.jpeg

    我们在控制台上输入命令bt,可以打印出来所有的frame。如果仔细观察,这些frame和左边红框里的堆栈是一致的。平时我们看到的左边的堆栈就是frame。

    平时Debug的时候我们经常做的事就是查看变量的值,通过frame variable命令,可以打印出当前frame的所有变量

    (lldb) frame variable
    (ViewController *) self = 0x00007fa158526e60
    (SEL) _cmd = "text:"
    (BOOL) ret = YES
    (int) a = 3
    

    八、breakpoint

    九、watchpoint

    breakpoint有一个孪生兄弟watchpoint。如果说breakpoint是对方法生效的断点,watchpoint就是对地址生效的断点

    如果我们想要知道某个属性什么时候被篡改了,我们该怎么办呢?有人可能会说对setter方法打个断点不就行了么?但是如果更改的时候没调用setter方法呢?
    这时候最好的办法就是用watchpoint。我们可以用他观察这个属性的地址。如果地址里面的东西改变了,就让程序中断

    • watchpoint set variable
      一般情况下,要观察变量或者属性,使用watchpoint set variable命令即可
      e.g: 观察self->_string
    (lldb) watchpoint set variable self->_string
    Watchpoint created: Watchpoint 1: addr = 0x7fcf3959c418 size = 8 state = enabled type = w
        watchpoint spec = 'self->_string'
        new value: 0x0000000000000000
    
    • watchpoint set expression
      如果我们想直接观察某个地址,可以使用watchpoint set expression
      e.g: 我们先拿到_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
    

    十、target

    对于target这个命令,我们用得最多的可能就是target modules lookup。由于LLDB给target modules取了个别名image,所以这个命令我们又可以写成image lookup。

    • image lookup --address
      当我们有一个地址,想查找这个地址具体对应的文件位置,可以使用image lookup --address,简写为image lookup -a
      e.g: 当我们发生一个crash
    2015-12-17 14:51:06.301 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
    

    我们可以看到是由于-[__NSArray0 objectAtIndex:]:超出边界而导致的crash,但是objectAtIndex:的代码到底在哪儿呢?

    (lldb) image lookup -a 0x000000010a1c3e36
          Address: TLLDB[0x0000000100000e36] (TLLDB.__TEXT.__text + 246)
          Summary: TLLDB`-[ViewController viewDidLoad] + 86 at ViewController.m:32
    

    根据0x000000010a1c3e36 -[ViewController viewDidLoad]里面的地址,使用image lookup --address查找,我们可以看到代码位置在ViewController.m里面的32行

    • image lookup --name
      当我们想查找一个方法或者符号的信息,比如所在文件位置等。我们可以使用image lookup --name,简写为image lookup -n。
    (lldb) image lookup -n dictionaryWithXMLString:
    2 matches found in /Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo:
            Address: BaiduIphoneVideo[0x00533a7c] (BaiduIphoneVideo.__TEXT.__text + 5414908)
            Summary: BaiduIphoneVideo`+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:] at XmlDictionary.m
             Module: file = "/Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo", arch = "armv7"
        CompileUnit: id = {0x00000000}, file = "/Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m", language = "Objective-C"
           Function: id = {0x23500000756}, name = "+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:]", range = [0x005a6a7c-0x005a6b02)
           FuncType: id = {0x23500000756}, decl = XmlDictionary.m:189, clang_type = "NSDictionary *(NSString *)"
             Blocks: id = {0x23500000756}, range = [0x005a6a7c-0x005a6b02)
          LineEntry: [0x005a6a7c-0x005a6a98): /Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m
             Symbol: id = {0x0000f2d5}, range = [0x005a6a7c-0x005a6b04), name="+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:]"
           Variable: id = {0x23500000771}, name = "self", type = "Class", location =  [sp+32], decl = 
           Variable: id = {0x2350000077e}, name = "_cmd", type = "SEL", location =  [sp+28], decl = 
           Variable: id = {0x2350000078b}, name = "string", type = "NSString *", location =  [sp+24], decl = XmlDictionary.m:189
           Variable: id = {0x23500000799}, name = "data", type = "NSData *", location =  [sp+20], decl = XmlDictionary.m:192
            Address: BaiduIphoneVideo[0x012ee160] (BaiduIphoneVideo.__TEXT.__text + 19810016)
            Summary: BaiduIphoneVideo`+[NSDictionary(XMLDictionary) dictionaryWithXMLString:] at XMLDictionary.m
             Module: file = "/Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo", arch = "armv7"
        CompileUnit: id = {0x00000000}, file = "/Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m", language = "Objective-C"
           Function: id = {0x79900000b02}, name = "+[NSDictionary(XMLDictionary) dictionaryWithXMLString:]", range = [0x01361160-0x0136119a)
           FuncType: id = {0x79900000b02}, decl = XMLDictionary.m:325, clang_type = "NSDictionary *(NSString *)"
             Blocks: id = {0x79900000b02}, range = [0x01361160-0x0136119a)
          LineEntry: [0x01361160-0x01361164): /Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m
             Symbol: id = {0x0003a1e9}, range = [0x01361160-0x0136119c), name="+[NSDictionary(XMLDictionary) dictionaryWithXMLString:]"
    

    东西有点多,我们只需关注里面的file这一行:

    CompileUnit: id = {0x00000000}, file = "/Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m", language = "Objective-C"
    CompileUnit: id = {0x00000000}, file = "/Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m", language = "Objective-C"
    

    可以清晰的看到,LLDB给我们找出来了这个方法的位置。
    当然这个命令也可以找到方法的其他相关信息,比如参数等.

    • image lookup --type
      当我们想查看一个类型的时候,可以使用image lookup --type,简写为image lookup -t:
      e.g: 我们来看看Model的类型:
    (lldb) image lookup -t Model
    Best match found in /Users/jiangliancheng/Library/Developer/Xcode/DerivedData/TLLDB-beqoowskwzbttrejseahdoaivpgq/Build/Products/Debug-iphonesimulator/TLLDB.app/TLLDB:
    id = {0x30000002f}, name = "Model", byte-size = 32, decl = Modek.h:11, clang_type = "@interface Model : NSObject{
        NSString * _bb;
        NSString * _cc;
        NSString * _name;
    }
    @property ( getter = name,setter = setName:,readwrite,nonatomic ) NSString * name;
    @end
    "
    

    可以看到,LLDB把Model这个class的所有属性和成员变量都打印了出来,当我们想了解某个类的时候,直接使用image lookup -t即可

    十一、Extension

    给UIApplicationMain设置一个断点,在断点中添加执行e @import UIKit。

    1122433-3f9b172265d0137b.jpg
    (lldb) p self.view.frame
    error: property 'frame' not found on object of type 'UIView *'
    error: 1 errors parsing expression
    (lldb) e @import UIKit(不需要写)
    (lldb) p self.view.frame
    (CGRect) $0 = (origin = (x = 0, y = 0), size = (width = 375, height = 667))
    

    常用的DeBug快捷键

    快捷键.png

    相关文章

      网友评论

        本文标题:iOS 常用的lldb命令

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