一、需要掌握的常用指令
1. p <expression>
- 用于执行一个表达式,可以为断点的程序添加一个额外的代码。
(lldb) p self.view.backgroundColor = [UIColor yellowColor];
(UICachedDeviceRGBColor *) $0 = 0x00006000020dafc0
解析:上述修改 view 背景的代码源代码中是不存在,但是我们过掉断点后,view 就会被修改成黄色。这个功能在我们深入调试某个程序,并且想修改代码一些逻辑的时候非常好用。
- 用于打印一个对象的地址
(lldb) p self.view
(UIView *) $1 = 0x00007f80104101a0
解析:仅用于打印对象的类型和地址值,思考和 po self.view
的区别?
- 以 16 进制的方式打印对象
(lldb) p age
(int) $0 = 10
(lldb) p/x age
(int) $1 = 0x0000000a
2. break set -n <functionName>
通过命令行给指定方法添加断点
- 给
ViewController
类中的touchesBegan:withEvent:
方法添加断点。如果没有添加类别说明,那么会给 iOS 项目中所有touchesBegan:withEvent:
方法添加断点。
(lldb) breakpoint set -n "[ViewController touchesBegan:withEvent:]"
Breakpoint 3: where = LLDBTest`-[ViewController touchesBegan:withEvent:]
+ 77 at ViewController.m:25:5, address = 0x00000001022b3edd
3. bt
是 thread backtrace
的简称,用于打印 栈帧
,帮助我们观察方法调用栈。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x0000000106d55eec LLDBTest`-[ViewController test](self=0x00007f9e00e054f0, _cmd="test") at ViewController.m:32:9
frame #1: 0x0000000106d55e8b LLDBTest`-[ViewController touchesBegan:withEvent:](self=0x00007f9e00e054f0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x0000600002d0c640) at ViewController.m:26:5
frame #2: 0x00007fff4718f0bf UIKitCore`forwardTouchMethod + 340
frame #3: 0x00007fff4718ef5a UIKitCore`-[UIResponder touchesBegan:withEvent:] + 49
frame #4: 0x00007fff4719df3e UIKitCore`-[UIWindow _sendTouchesForEvent:] + 1867
frame #5: 0x00007fff4719fb26 UIKitCore`-[UIWindow sendEvent:] + 4596
frame #6: 0x00007fff4717b1a7 UIKitCore`-[UIApplication sendEvent:] + 356
frame #7: 0x00007fff471faa18 UIKitCore`__dispatchPreprocessedEventFromEventQueue + 6847
frame #8: 0x00007fff471fd4de UIKitCore`__handleEventQueueInternal + 5980
frame #9: 0x00007fff23afbac1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #10: 0x00007fff23afb9ec CoreFoundation`__CFRunLoopDoSource0 + 76
frame #11: 0x00007fff23afb1c4 CoreFoundation`__CFRunLoopDoSources0 + 180
frame #12: 0x00007fff23af5ecf CoreFoundation`__CFRunLoopRun + 1263
frame #13: 0x00007fff23af56b6 CoreFoundation`CFRunLoopRunSpecific + 438
frame #14: 0x00007fff3815cbb0 GraphicsServices`GSEventRunModal + 65
frame #15: 0x00007fff47162a67 UIKitCore`UIApplicationMain + 1621
frame #16: 0x0000000106d561e4 LLDBTest`main(argc=1, argv=0x00007ffee8ea8d28) at main.m:18:12
frame #17: 0x00007fff5123bcf5 libdyld.dylib`start + 1
frame #18: 0x00007fff5123bcf5 libdyld.dylib`start + 1
4. frame variable
用于打印断点所在方法内所有局部变量的值
(lldb) frame variable
(ViewController *) self = 0x00007f9e00e054f0
(SEL) _cmd = "test"
(int) a = 1072693248
(int) b = 0
5. 控制断点走向的指令
thread continue
、continue
、c
:程序继续运行
thread step-over
、next
、n
:单步运行,把自海曙当做整体一步执行
thread step-in
、step
、s
: 单步运行,遇到子函数会进入子函数
thread step-out
、finish
:直接执行完当前函数的所有代码,返回到上一个函数
si
、ni
和 s
、n
类似
- s 、n 是源码级别指令
- si、ni 是汇编级别指令
6. 内存断点,在内存数据发生变化的时候触发,方便我们观察指定值什么时候改变。有点类似于复写了 set 方法,并且在 set 方法内部打断点。
watchpoint set variable 变量
(lldb) watchpoint set variable self->_age
Watchpoint created: Watchpoint 1: addr = 0x7ff5a2e037d0 size = 4 state = enabled type = w
watchpoint spec = 'self->_age'
new value: 0
- 触发修改 age 值的时候
Watchpoint 1 hit:
old value: 0
new value: 10
二、汇编调试指令
1. x/4gx 对象 || 地址
- 表示输出4个16进制的8字节地址空间(x表示16进制,4表示4个,g表示8字节为单位,等同于x/4xg 对象)
(lldb) x/4gx p
0x10064c3e0: 0x0000000f0000000a 0x3000000010064de9
0x10064c3f0: 0x75636f44534e5b2d 0x69766552746e656d
(lldb) x/4gx 0x10064c3e0
0x10064c3e0: 0x0000000f0000000a 0x3000000010064de9
0x10064c3f0: 0x75636f44534e5b2d 0x69766552746e656d
2. 查看寄存器存的值 register read rax
(lldb) register read rax
rax = 0x0000000000000000
(lldb) register read
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0x0000000000000000
rcx = 0x000000010064c3e0
rdx = 0x0000000000000000
rdi = 0x00007ffeefbff3a0
rsi = 0x0000000000000000
rbp = 0x00007ffeefbff4a0
rsp = 0x00007ffeefbff460
r8 = 0x00000000000130a8
3. 给寄存器赋值 register write rax 15
(lldb) register read rax
rax = 0x0000000000000000
(lldb) register write rax 0x10
(lldb) register read rax
rax = 0x0000000000000010
(lldb) register write rax 15
(lldb) register read rax
rax = 0x000000000000000f
4. AT&T 下的常见寄存器以及作用?
-
%rax
做为函数的返回值(同 8086 汇编的 ax) -
%rsp
指向栈顶(同 8086 汇编的 ss:sp) -
%rdi, %rsi, %rdx, %rcx, %r8, %r9
等寄存器用于存放函数参数
5. AT&T 表示字节数的单位?
-
b:
b=byte,8bit,1 一个字节 -
s:
s=short,16bit,2 个字节 -
l:
l=long,32bit,4 个字节 -
q:
q=quad,64bit,8 个字节
6. lea 和 mov 两个汇编指令的区别?
-
lea:load effective address
,操作的是地址 -
mov:load effective address
,操作的是地址所存放的数据
7. 内存地址的最小单位是什么?
- 字节:每一个字节都有自己的内存地址
8. CPU 大小端模式中的比较常见的是哪种?牢记的口诀是什么?每个字节对应16进制和2进制分别多少位?(这个还没完全记住,笨啊)
- 现在 CPU 基本上都是
小端模式
- 口诀:
高高低低 ;高字节放高地址,低字节放低地址。
- 16进制:2 位;二进制:8 位;