LLVM 是一个模块化和可重用的编译器和工具链技术的集合,创始人是 Chris Lattner,也是Swift之父
LLDB 是 LLVM 的子项目,基于LLVM提供的库和Clang构建的优秀的本地调试器。
在命令行中调试程序
在终端中使用LLDB调试器, 需要了解以下内容.
- 加载程序以备调试
- 将一个运行的程序绑定到LLDB
$ lldb /Projects/Sketch/build/Debug/Sketch.app
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
- 设置断点和观察点
给main.m文件中的12行设置断点
(lldb) breakpoint set --file main.m --line 12
设置观察点
作为断点的补充, LLDB支持观察点以在不中断程序运行的情况下监测一些变量。例如,我们可以使用以下命令来监测名为global的变量的写操作,并在(global==5)为真时停止监测
(lldb) watch set var global
Watchpoint created: Watchpoint 1: addr = 0x100001018 size = 4 state = enabled type = w
declare @ '/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'
(lldb) watch modify -c '(global==5)'
(lldb) watch list
- 控制程序的执行
启动程序
(lldb) process launch
(lldb) run
(lldb) r
- 在调试的程序中导航
(lldb) thread continue
Resuming thread 0x2c03 in process 46915
Resuming process 46915
- 检查状态和值的变量
查看线程状态
(lldb) thread list
查看调用栈状态
(lldb) frame variable self
(SKTGraphicView *) self = 0x0000000100208b40
- 执行替代代码
expression命令不仅会改变调试器中的值,还改变了程序中的实际值
(lldb) exp a = 10
(NSInteger) $0 = 10
(lldb) exp b = 100
(NSInteger) $1 = 100
2015-01-25 14:00:41.313 test[18064:71466] a + b = 110, abc
在Xcode中使用LLDB调试器本质上和在命令行中调试程序一样(Xcode只是一个GUI, 图形操作界面), 以上的步骤完全一样, 相关的指令可以参考苹果官方文档.
在Xcode中调试程序
help命令可以列出能使用的命令列表
(lldb) help
这里介绍一些常用命令的用法
1. print指令
- print命令会打印出对象的类型和相关属性.
- print命令的别名有prin, pri, p,
- po命令对于继承自NSObject的对象,会打印出description中的内容,类似于print函数, 对于struct, 会打印出属性
Swift中的打印
(lldb) print a
(Int) $R1 = 10
(lldb) print p
(LCCustomTools_Swift.Person) $R2 = (name = "lucy", age = 12)
(lldb) prin a
(Int) $R3 = 10
(lldb) pri a
(Int) $R4 = 10
(lldb) p a
(Int) $R5 = 10
// 结构体
(lldb) po p
▿ Person
- name : "lucy"
- age : 12
// class
(lldb) po p2
<PersonClass: 0x60000044a830>
(lldb)
OC中的打印
(lldb) p a
(int) $0 = 10
(lldb) p person
(Person *) $1 = 0x0000608000010780
(lldb) po person
<Person: 0x608000010780>
2. 打印视图的层级结构
OC
(lldb) po [self.view recursiveDescription]
Swift
(lldb) po view. recursiveDescription
<UIView: 0x7fec9152ce10; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x600000032120>>
| <UIButton: 0x7fec9152b0b0; frame = (114 76; 92 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031520>>
| <UIButton: 0x7fec9152b570; frame = (130 152; 60 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031a20>>
| <UIButton: 0x7fec9152c7d0; frame = (177.583 229; 86.3333 60); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031f00>>
| | <UIImageView: 0x7fec9152e240; frame = (10.6667 15; 30 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x600000033920>>
| | <UIButtonLabel: 0x7fec91530d20; frame = (41 20; 34.6667 20.3333); text = '撸串'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60000008ce90>>
| | | <_UILabelContentLayer: 0x600000035140> (layer)
3. 打印视图控制器的层级结构
OC
(lldb) po [UIWindow valueForKeyPath:@"keyWindow.rootViewController._printHierarchy"]
Swift
(lldb) po UIWindow.valueForKeyPath("keyWindow.rootViewController._printHierarchy")
<NavigationController 0x7fcf83807a00>, state: appeared, view: <UILayoutContainerView 0x7fcf82c09900>
| <ViewController 0x7fcf82d09900>, state: appeared, view: <UIView 0x7fcf82c0c420>
| <Button_ViewController 0x7fcf82e02320>, state: disappeared, view: <UIView 0x7fcf82d223a0> not in the window
4. 格式化输出
// 16进制
(lldb) p/x p2.age
(Int) $R2 = 0x000000000000000c
// 10进制
(lldb) p/d p2.age
(Int) $R3 = 12
// 8进制
(lldb) p/o p2.age
(Int) $R4 = 014
(lldb) p/x 0x7fcf83807a00
(Int) $R5 = 0x00007fcf83807a00
5. expression命令
expression的简写有exp, e。可以用expression来声明新的变量,也可以改变已有变量的值。我们看到e声明的都是$
开头的变量。我们在使用时也需要加上$
符号。
(lldb) e let $arr = ["a", "b", "c"]
(lldb) p $arr
([String]) $R0 = 3 values {
[0] = "a"
[1] = "b"
[2] = "c"
}
(lldb) po $arr[0]
"a"
6. image命令
image命令可以用来寻找栈地址对应的代码位置
NSArray *arr = @[@"a", @"b"];
NSLog(@"%@", arr[2]);
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndexedSubscript:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x000000011045d12b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010faf1f41 objc_exception_throw + 48
2 CoreFoundation 0x000000011049d0cc _CFThrowFormattedException + 194
3 CoreFoundation 0x0000000110510890 +[__NSArrayI allocWithZone:] + 0
4 LCCustomTools_OC 0x000000010f1cf878 -[AppDelegate application:didFinishLaunchingWithOptions:] + 184
5 UIKit 0x0000000110fe5bca -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 299
6 UIKit 0x0000000110fe7648 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4113
7 UIKit 0x0000000110fecaeb -[UIApplication _runWithMainScene:transitionContext:completion:] + 1720
...
根据以上信息, 可以知道问题出在[AppDelegate application:didFinishLaunchingWithOptions:]
, 但是不知道具体在哪一行.
通过以下命令找到出错位置
(lldb) image lookup --address 0x000000010f1cf878
Address: LCCustomTools_OC[0x0000000100009878] (LCCustomTools_OC.__TEXT.__text + 32824)
Summary: LCCustomTools_OC`-[AppDelegate application:didFinishLaunchingWithOptions:] + 184 at AppDelegate.m:30
问题出在30行
网友评论