LLDB常用命令和用法

前言

LLDB是Xcode的一个调试工具,刚开始只知道一个bt命令,到后来的po,再到后来的breakpoint,越来越觉得LLDB的强大。

慢慢的了解多了,才觉得之前每次修改代码、编译、运行、查看结果是多么的愚蠢和耗时!

示例

下面看看LLDB都有哪些神奇的用处,下面写了几行简单的代码,主要用来演示,程序已经停止在打了断点的那一行,控制台是打开状态,我们可以和调试器进行交互。

我们先来输个po [[UIWindow keyWindow] recursiveDescription] :

可以清楚的看到程序视图的层级关系。

下面我们重点介绍下常用命令:

print

print就是打印,和C的printf,Object-C的NSLog差不多。
其实print是另外一个命令expression其中一种用法的缩写,这个待会儿再说。

我们先打印下这里的index看看:

可以看到,print还可以打印表达式。

tips
  • LLDB是会做前缀匹配的,所以不论你输入print/pri/p都是可以的,但是pr确实不行的,因为LLDB不知道pr到底是应该代表print还是process,幸运的是p可以,这就够了,哈哈哈。

  • 任何以美元符开头的东西都是存在于 LLDB 的命名空间的,它们是为了帮助你进行调试而存在的。这里的$0$1是用来指向结果的,我们可以输入print $1print $1 + 100就明白了。

expression

当我们需要改变变量的值得时候,就要用到这个命令了,而且它改变的不仅仅是调试器里的值,程序里的值也改变了:

tip
  • 下面用 e 表示 expressionp 表示 print
  • 其实 print == expression -- ,我们在调试器中输入help print可以看到'print' is an abbreviation for 'expression --'

po[print object]

当我们用print去打印对象时看起来就很别扭了, 我们想看的当然不是这个了,我们想看对象的description的内容。来看看 ppo 打印对象时的区别:

tips
  • poe -o -- 的缩写

continue, step over, step into, step out

这几个命令对应的就是调试条的四个按钮和Debug菜单下面的4个命令

第一个,continue 按钮,会取消程序的暂停,允许程序正常执行 (要么一直执行下去,要么到达下一个断点)。在 LLDB 中,你可以使用 process continue 命令来达到同样的效果,它的别名为 continue,或者也可以缩写为 c

第二个,step over 按钮,会以黑盒的方式执行一行代码。如果所在这行代码是一个函数调用,那么就不会跳进这个函数,而是会执行这个函数,然后继续。LLDB 则可以使用 thread step-overnext,或者 n 命令。

第三个,step in 按钮,跳进一个函数调用来调试或者检查程序的执行情况。在LLDB中使用 thread step instep,或者 s 命令。

第四个,step out 按钮,如果你不小心跳进一个函数,但实际上你想跳过它,常见的反应是重复的运行 n 直到函数返回。其实这种情况,step out 按钮是你的救世主。它会继续执行到下一个返回语句 (直到一个堆栈帧结束) 然后再次停止, LLDB中使用 thread step-out 或者 finish 命令。

tips
  • 注意,当前行不是函数调用时,nextstep 效果是一样的。

Thread Return

调试的时候是不是经常需要短路一个逻辑 if (1 || success) { ... } 或者伪造一个函数的实现:

- (BOOL)shouldStop:(int)target {
    return YES;

    /***
    ...
    ***/
}

短路逻辑可以用上面的expression success = YES来实现,thread return就可以轻松的伪造函数。 它有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,然后立刻执行返回命令,跳出当前栈帧。这意味这函数剩余的部分不会被执行。

示例:

可以看到我们在 index=1 的时候使用了 thread return YES 成功的让 shouldStop 返回了 TRUE,是不是很方便,再也不用改代码、编译、执行、看结果是什么样的。

breakpoint

查看当前的断点:breakpoint list

(lldb) breakpoint list
Current breakpoints:  
1: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 28, exact_match = 0, locations = 1, resolved = 1, hit count = 3

  1.1: where = LLDBTest`-[ViewController task] + 40 at ViewController.m:28, address = 0x000000010be40598, resolved, hit count = 3 

2: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 36, exact_match = 0, locations = 1, resolved = 1, hit count = 2

  2.1: where = LLDBTest`-[ViewController shouldStop:] + 15 at ViewController.m:36, address = 0x000000010be405ff, resolved, hit count = 2 

(lldb) 

关闭断点:breakpoint disable

(lldb) breakpoint disable 1.1
1 breakpoints disabled.  
(lldb) br list
Current breakpoints:  
1: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 28, exact_match = 0, locations = 1

  1.1: where = LLDBTest`-[ViewController task] + 40 at ViewController.m:28, address = 0x000000010be40598, unresolved, hit count = 3  Options: disabled 

2: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 36, exact_match = 0, locations = 1, resolved = 1, hit count = 2

  2.1: where = LLDBTest`-[ViewController shouldStop:] + 15 at ViewController.m:36, address = 0x000000010be405ff, resolved, hit count = 2 

(lldb) 

可以看到1.1的断点是unresolved Options:disabled

开启断点:breakpoint enable

(lldb) br enable 1.1
1 breakpoints enabled.  
(lldb) br li
Current breakpoints:  
1: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 28, exact_match = 0, locations = 1, resolved = 1, hit count = 3

  1.1: where = LLDBTest`-[ViewController task] + 40 at ViewController.m:28, address = 0x000000010be40598, resolved, hit count = 3 

2: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 36, exact_match = 0, locations = 1, resolved = 1, hit count = 2

  2.1: where = LLDBTest`-[ViewController shouldStop:] + 15 at ViewController.m:36, address = 0x000000010be405ff, resolved, hit count = 2 

(lldb)

增加断点:breakpoint set * 某个文件某一行加断点br set -f ViewController.m -l 30

(lldb) br set -f ViewController.m -l 30
Breakpoint 7: where = LLDBTest`-[ViewController task] + 92 at ViewController.m:30, address = 0x000000010be405cc  
(lldb) br li
Current breakpoints:  
7: file = 'ViewController.m', line = 30, exact_match = 0, locations = 1, resolved = 1, hit count = 0  
  7.1: where = LLDBTest`-[ViewController task] + 92 at ViewController.m:30, address = 0x000000010be405cc, resolved, hit count = 0 

(lldb) 
  • 设置某个函数的断点:set -F function
(lldb) br set -F shouldStop: 
Breakpoint 4: where = LLDBTest`-[ViewController shouldStop:] + 15 at ViewController.m:36, address = 0x000000010fd555ff  
(lldb) br set -F "-[NSArray objectAtIndex:]"
Breakpoint 5: where = CoreFoundation`-[NSArray objectAtIndex:], address = 0x00000001109201e0  
tips
  • 注意,大写的 Ffunction name,小写的 ffilename

说到断点必须要提到断点行为 Action 。譬如我们示例中的 NSLog(@"%d", index); 这句也是用来调试的,其实呢我们可以用断点行为来实现:

![](http://noti.qiniudn.com/4309b8975183aa347e62838077fdf0df.png)

是不是很方便呢,发挥你的想象吧!

当然了,还可以添加短点的条件,比如上面这个断点我想让 index = 20 的时候再触发这个断点:

(lldb) br modify -c "index == 20" 1.1
(lldb) br list
Current breakpoints:  
1: file = '/Users/wentian/project/github/LLDBTest/LLDBTest/ViewController.m', line = 28, exact_match = 0, locations = 1, resolved = 1, hit count = 1

  1.1: where = LLDBTest`-[ViewController task] + 40 at ViewController.m:28, address = 0x000000010cf62598, resolved, hit count = 1 
Condition: index == 20  

改变UI

调试器甚至还可以改变UI,下面看两个例子:

  • 改变view颜色

  • push一个viewcontroller

  • 刷新UI e (void)[CATransaction flush]

参考资料:

  1. GDB TO LLDB COMMAND MAP
  2. LLDB in Debugging
  3. LLDB Quick Start Guide
  4. LLDB Tutorial