Xcode LLDB 常用指令

1,617 阅读4分钟

在日常开发中,熟练使用LLDB可以极大的提高工作效率,下面介绍几个常用的指令。

expr

exprexpression的缩写,作用是执行一个表达式,并将表达式返回的结果输出。可以理解为:实时的执行代码逻辑,修改内存中变量的值,并打印结果。
文档解释:

expression        -- Evaluate an expression on the current thread.  Displays
                       any returned value with LLDB's default formatting.
在当前线程上执行表达式。以LLDB默认格式显示返回值

expression的完整语法:expression <cmd-options> -- <expr>
expression <命令选项> “-- --”分隔符 执行的参数或表达式

(lldb) expression b.name = @"xx"
(NSTaggedPointerString *) $7 = 0x284b110ff4220251 @"xx"
(lldb) expr b.height = 188
(CGFloat) $8 = 188
(lldb) 

expression是lldb里面最重要的命令。他能实现2个非常重要的功能:

  • 执行表达式。 在程序暂停时,可以通过lldb调试器直接修改页面属性,而不需要重新运行程序
// 改变颜色
(lldb) expression -- self.view.backgroundColor = [UIColor redColor]
// 刷新界面
(lldb) expression -- (void)[CATransaction flush]
  • 输出返回值
(lldb) expression -- self.view
(UIView *) $1 = 0x00007fe322c18a10

expression --的别名(--表示不再接受命令选项)是对expression --的一层封装,分别为p、print、call。

pop

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

  • p通常用于打印基本数据类型的值。这个指令会默认生出一个临时变量,如$1。
po       -- Evaluate an expression on the current thread. 
            Displays any returned value with formatting
            controlled by the type's author.
在当前线程上执行表达式。显示返回值,返回值格式格式由调用者控制
(lldb) p x //x为变量名称
(XTeacher *) $5 = 0x0000000102a8db20 //XTeacher 为打印的对象类型,$5为临时变量
  • po 打印变量的内容,如果是对象,其打印的内容由 -debugDescription 决定。
(lldb) po x
<XTeacher: 0x102a8db20>

在调试器中输入 e @import UIKit 可以打印出view的frame

(lldb) e @import UIKit
(lldb) po self.view.frame
(origin = (x = 0, y = 0), size = (width = 375, height = 667))

call

执行一行代码,类似于expression。

call                 -- Evaluate an expression on the current thread. 
                        Displays any returned value with LLDB's default
                        formatting.
(lldb) call self.view.backgroundColor = [UIColor redColor];

breakpoint

1.breakpoint set断点设置,有多种断点设置的方式

  • 使用-n设置方法名断点
(lldb) breakpoint set -n viewWillAppear: 给所有类中的viewWillAppear:设置一个断点
  • 使用-f设置文件断点
(lldb) breakpoint set -f ViewController.m -n viewWillAppear:
  • 使用-l设置行数断点
(lldb) breakpoint set -f ViewController.m -l 40
  • 使用-c设置条件断点
selector:方法接受一个ret的参数,我们想让ret == YES的时候程序中断
(lldb) breakpoint set -n selector: -c ret == YES
  • 使用-o设置单次断点
(lldb) breakpoint set -n selector: -o //只会中断一次

2.breakpoint delete删除断点

  • 删除ID为1的断点
(lldb) breakpoint delete 1
  • 删除所有断点
(lldb) breakpoint delete 
About to delete all breakpoints, do you want to do that?: [Y/n] y
All breakpoints removed. (1 breakpoint)
  • 删除所有断点,忽略提示
(lldb) breakpoint delete -f
All breakpoints removed. (1 breakpoint)

3.breakpoint list显示所有断点

(lldb) breakpoint list
Current breakpoints:
1: file = '工程路径/objc4-756.2/runtime/objc-runtime-new.mm', line = 6987, exact_match = 0, locations = 0 (pending)


2: file = '工程路径/objc4-756.2/runtime/NSObject.mm', line = 1738, exact_match = 0, locations = 0 (pending)


3: file = '工程路径/Test/main.m', line = 35, exact_match = 0, locations = 1, resolved = 1, hit count = 1

3.1: where = Test`main + 186 at main.m:35:22, address = 0x0000000100000b6a, resolved, hit count = 1 

watchpoint

如果breakpoint是对方法生效的断点,watchpoint就是对地址生效的断点 在开发中,我们检测一个属性的变化是通常是通过set方法,如果属性的修改没有经过set方法,就可以使用watchpoint对内存检测,一旦内存中的值修改,就会触发断点,中断程序。 1.watchopint set设置观测点

  • watchopint set variable <变量参数>为变量设置观测点
    atchpoint set variable self->_variable属性需要在前面添加下滑线
(lldb) watchpoint set variable b->_age
Watchpoint created: Watchpoint 1: addr = 0x100658858 size = 8 state = enabled type = w
    declare @ '工程路径/Test/main.m:30'
    watchpoint spec = 'b->_age'
    new value: 30
2020-01-20 14:58:18.344082+0800 Test[16750:838229] <XTeacher: 0x100658850>

Watchpoint 1 hit:
old value: 30
new value: 18
  • watchopint set expression <变量地址>为变量地址设置观测点
(lldb) p b
(XTeacher *) $0 = 0x000000010387af70
(lldb) watchpoint set expression 0x000000010387af70
Watchpoint created: Watchpoint 1: addr = 0x10387af70 size = 8 state = enabled type = w
    new value: 8303516107941037
2020-01-20 15:06:32.342573+0800 Test[16819:846411] <XTeacher: 0x10387af70>

Watchpoint 1 hit:
old value: 8303516107941037
new value: 26317914617423021
  • watchpoint command add为观测点添加命令
    向ID为1的观测点添加一条‘po self’命令
watchpoint command add -o 'po self' 1

向ID为1的观测点添加多条命令

(lldb) watchpoint command add 1
Enter your debugger command(s). Type 'DONE' to end.
> po self
> continue
> DONE
  • watchpoint command list查询观测点命令列表
  • watchpoint command delete删除观测点命令
    (lldb) watchpoint command delete 1删除观测点ID为1的观测点的命令列表
  • watchpoint list查询工程中的所有观测点列表
  • watchpoint delete 删除观测点ID为:1的观测点
(lldb) watchpoint delete 1

删除工程中的观测点

(lldb) watchpoint delete 
About to delete all watchpoints, do you want to do that?: [Y/n] y
All watchpoints removed. (2 watchpoints)

register read

返回当前线程通用寄存器的值(对64为对应x0-x31)

(lldb) register read
General Purpose Registers:
        x0 = 0x0000000102905540
        x1 = 0x00000001e1fd3c56  
        x2 = 0x0000000000000001
        x3 = 0x000000016dac7c40
        x4 = 0x0000000000000010
        x5 = 0x000000016dac784f
        x6 = 0x000000016dac7940
        x7 = 0x0000000000000000
        x8 = 0x000000010233cff8  "viewDidLoad"
        x9 = 0x000000010233d038  (void *)0x000000010233d050: ViewController
       ...

可以读取某一个寄存器的值

(lldb) register read x10
     x10 = 0x0000000000000056

memory read (简写x)

  • 以给定格式读取给定内存地址数据
(lldb) memory read -f s $x1
或者
(lldb) x -f s $x1
或者
(lldb) x/s $x1
  • 读取栈中所有值,即sp和fp连续内存区域值
(lldb) x -f A $sp $fp
  • 读取目标内存指令,比如x/10xg sp
    10xg中10代表数量,x代表数据格式,g代表每块8个字节数 10xg的意思就是以8个字节为一段,16进制格式,显示10段sp起始地址之后的内容
数量是指读取从该对象起始地址或该内存地址起始地址后多长的地址

格式
x是16进制
f是浮点
d是10进制

字节大小
b:byte 1字节
h:half word 2字节
w:word 4字节
g:giant word 8字节

参考:
刹那_芳华 ---- LLDB
CoderHG ---- Xcode 常用 LLDB 指令
LLDB官网