iOS之LLDB常用调试命令
LLDB是个开源的内置于XCode的调试工具,这里来理一理常用用法。
lldb对于命令的简称,是头部匹配方式,只要不混淆,你可以随意简称某个命令。结果为在xcode下验证所得,可能与其它平台有所误差。
1 打印值、修改值、调用方法
1.1 p、po 打印值
打印相关的命令有:p、po。
p 和 po 的区别在于使用 po 只会输出对应的值,而 p 则会返回值的类型以及命令结果的引用名。
(lldb) p width
(CGFloat) $10 = 70
(lldb) po width
70
(lldb) p endTime
(__NSCFString *) $14 = 0x0000608000437660 @"08-11 11:43"
(lldb) po endTime
08-11 11:43
对比结果:
po:输出值
p:输出值+值类型+引用名+内存地址(xcode中有内存地址,其它平台不确定)
除此之外,p还隐藏了一个有意思的功能,常量的进制转换:
//默认打印为10进制
(lldb) p 100
(int) $8 = 100
//转16进制
(lldb) p/x 100
(int) $9 = 0x00000064
//转8进制
(lldb) p/o 100
(int) $10 = 0144
//转二进制
(lldb) p/t 100
(int) $2 = 0b00000000000000000000000001100100
//字符转10进制数字
(lldb) p/d 'A'
(char) $7 = 65
//10进制数字转字符
(lldb) p/c 66
(int) $10 = B\0\0\0
1.2 expression 修改参数值
感觉exp命令是调试过程中最有价值有命令了,它可以打印值、修改值。
//expression打印值
(lldb) expression width
(CGFloat) $5 = 67
//expression修改值
(lldb) expression width = 80
(CGFloat) $6 = 80
//打印修改后结果
(lldb) p width
(CGFloat) $7 = 80
(lldb)
expression:同样可以输出值+值类型+引用名,但其一般用于修改。
1.3 call 方法调用
在断点调用某个方法,并输出此方法的返回值。
(lldb) call width
(CGFloat) $12 = 70
(lldb) call endTime
(__NSCFString *) $16 = 0x0000608000437660 @"08-11 11:43"
call:同样为输出值+值类型+引用名
2 Thread
2.1 堆栈打印 thread backtrace
如果嫌堆栈打印太长,可以加一个值限制,如bt 10,只打印
(lldb) bt 10
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001005e4906 DiDi`-[FW_HomeCell_HotBill setDataSource:](self=0x00007fd3938a7800, _cmd="setDataSource:", dataSource=0x00006080001c8bb0) at FW_HomeCell.m:357
frame #1: 0x00000001009a9fd7 DiDi`-[FW_MyHomeTableView tableView:cellForRowAtIndexPath:](self=0x00007fd3921fec00, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007fd3921fec00, indexPath=0xc000000000000316) at FW_MyHomeTableView.m:247
frame #2: 0x00000001055a2ab2 UIKit`-[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 750
frame #3: 0x00000001055a2cf8 UIKit`-[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
frame #4: 0x0000000105577639 UIKit`-[UITableView _updateVisibleCellsNow:isRecursive:] + 2845
frame #5: 0x00000001055abccc UIKit`-[UITableView _performWithCachedTraitCollection:] + 111
frame #6: 0x0000000105592e7a UIKit`-[UITableView layoutSubviews] + 233
frame #7: 0x00000001054f955b UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
frame #8: 0x0000000105114904 QuartzCore`-[CALayer layoutSublayers] + 146
frame #9: 0x0000000105108526 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 370
2.2 thread return 跳出当前方法的执行
Debug的时候,也许会因为各种原因,我们不想让代码执行某个方法,或者要直接返回一个想要的值。这时候就该thread return上场了。
有返回值的方法里,如:numberOfSectionsInTableView:,直接thread return 10,就可以直接跳过方法执行,返回10.
//跳出方法
(lldb) thread return
//让带有返回int值的方法直接跳出,并返回值10
(lldb) thread return 10
2.3 流程控制
实际上使用xcode自带的可视化工具来控制“继续”“暂停”“下一步”“进入”“跳出”更简单
继续:continue, c
下一步:next, n
进入:step, s
跳出:finish, f
2.4 跳帧 frame select N
2.1中打印有10帧,如果我想跳转到第1帧:frame select 1
(lldb) frame select 1
frame #1: 0x0000000105e91c3c DiDi`-[FW_HomeViewController tableView:cellForRowAtIndexPath:](self=0x00007fbf9f73b410, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007fbfa11dc400, indexPath=0xc000000000a00316) at FW_HomeViewController.m:597
594 break;
595
596 case 3: {
-> 597 cell.[4md[0mataSource = _hotBills[indexPath.row];
598 cell.textSelect = ^(UITextField *text) {
599 weakSelf.curruntText = text;
600 };
2.5 查看帧变量 frame variable
(lldb) frame variable
(FW_HomeViewController *) self = 0x00007faccbf587d0
(SEL) _cmd = "tableView:cellForRowAtIndexPath:"
(UITableView *) tableView = 0x00007faccd09b400
(NSIndexPath *) indexPath = 0xc000000000000316
(FW_HomeViewController *) weakSelf = 0x00007faccbf587d0
(FW_HomeCell_HotBill *) cell = 0x00007faccc101a00
(UIView *) model = 0x00007fff52c13d90
(FW_HomeCell_HotBill *) billCell = 0x00000001124e99f6
3 Image
3.1 image lookup -address 查找崩溃位置
当你遇见数组崩溃,你又没有找到崩溃的位置,只扔给你一堆报错信息,这时候image lookup来帮助你。如下
0 CoreFoundation 0x0000000103209b0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00000001079db141 objc_exception_throw + 48
2 CoreFoundation 0x000000010313effb -[__NSArrayM objectAtIndex:] + 203
3 DiDi 0x00000001009a9f3a -[FW_MyHomeTableView tableView:cellForRowAtIndexPath:] + 1322
4 UIKit 0x00000001055a2ab2 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 750
5 UIKit 0x00000001055a2cf8 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
6 UIKit 0x0000000105577639 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2845
7 UIKit 0x00000001055abccc -[UITableView _performWithCachedTraitCollection:] + 111
8 UIKit 0x0000000105592e7a -[UITableView layoutSubviews] + 233
9 UIKit 0x00000001054f955b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
10 QuartzCore 0x0000000105114904 -[CALayer layoutSublayers] + 146
寻找自己项目的标识,看到frame3位置,你只需这样查找位置:
image lookup -a 0x00000001009a9f3a
Address: DiDi[0x0000000100609f3a] (DiDi.__TEXT.__text + 6323194)
Summary: DiDi`-[FW_MyHomeTableView tableView:cellForRowAtIndexPath:] + 1322 at FW_MyHomeTableView.m:243
项目中FW_MyHomeTableView.m:243,perfect!
3.2 image lookup -name 查找方法来源
此命令可以用来查找方法的来源。包括在第三方SDK中的方法,也能被查到。
例:查找transformOtherModelToSuit:
(lldb) image lookup -n transformOtherModelToSuit:
1 match found in /Users/xxx/Library/Developer/Xcode/DerivedData/DiDi-cwpbvvyvqmeijmcjnneothzuthsy/Build/Products/Debug-iphonesimulator/DiDi.app/DiDi:
Address: DiDi[0x0000000100293d60] (DiDi.__TEXT.__text + 2693664)
Summary: DiDi`+[FW_BetFunction transformOtherModelToSuit:] at FW_BetFunction.m:107
3.3 image lookup –type 查看成员
查看某个class的所有属性和成员变量。不过貌似frameWork库中文件不能查看。
(lldb) image lookup -t MatchEvent
1 match found in /Users/xxxx/Library/Developer/Xcode/DerivedData/DiDi-cwpbvvyvqmeijmcjnneothzuthsy/Build/Products/Debug-iphonesimulator/DiDi.app/DiDi:
id = {0x00433d32}, name = "MatchEvent", byte-size = 48, decl = MatchEvent.h:11, compiler_type = "@interface MatchEvent : NSObject{
BOOL _isHome;
NSString * _playerName;
NSString * _timePoint;
NSString * _eventType;
NSString * _eventDesc;
}
@property ( getter = isHome,setter = setIsHome:,assign,readwrite,nonatomic ) BOOL isHome;
@property ( getter = playerName,setter = setPlayerName:,readwrite,copy,nonatomic ) NSString * playerName;
@property ( getter = timePoint,setter = setTimePoint:,readwrite,copy,nonatomic ) NSString * timePoint;
@property ( getter = eventType,setter = setEventType:,readwrite,copy,nonatomic ) NSString * eventType;
@property ( getter = eventDesc,setter = setEventDesc:,readwrite,copy,nonatomic ) NSString * eventDesc;
@end"
4 breakpoint
4.1 文件名+行号 breakpoint set -f xxx -l xxx
我们平时操作xcode,在某一行点下断点,其实操作的就是这个命令。
(lldb) breakpoint set -f FW_ProfilesDetailModel.m -l 95
Breakpoint 3: where = DiDi`-[FW_ProfilesDetailModel incomeRate] + 27 at FW_ProfilesDetailModel.m:96, address = 0x0000000105b404bb
4.2 函数名断点
4.2.1 方法名断点 breakpoint set -n 方法名
(lldb) breakpoint set -n viewDidLoad
Breakpoint 4: 414 locations.
Tips:这里要说一下,xcode其实也有函数名断点,不过用breakpoint set -n实现,比xcode下断点快N倍,不过xcode下的断点还给提示所有断到的位置。
4.2.2 类中方法断点 breakpoint set -n “-[类名 方法名]”
(lldb) breakpoint set -n "-[FW_MyHomeViewController viewDidLoad]"
Breakpoint 8: where = DiDi`-[FW_MyHomeViewController viewDidLoad] + 20 at FW_MyHomeViewController.m:58, address = 0x0000000105aec944
注意:-[FW_MyHomeViewController viewDidLoad],外面一定要加双引
号,不然会误识别为-[FW_MyHomeViewController`
4.3 条件断点 breakpoint set -c “xxxx”
和xcode中symbolic Breakpoint功能相同,我在FW_HomeCell.m 362行下断点,但又想过滤仅width>68的状态,操作如下:
breakpoint set -f FW_HomeCell.m -l 362 -c "width > 68"
Breakpoint 5: where = DiDi`-[FW_HomeCell_HotBill setDataSource:] + 2006 at FW_HomeCell.m:363, address = 0x000000010d22e0a6
4.4 查看断点列表 breakpoint list
(lldb) breakpoint list
Current breakpoints:
8: name = '-[FW_MyHomeViewController viewDidLoad]', locations = 1, resolved = 1, hit count = 2
8.1: where = DiDi`-[FW_MyHomeViewController viewDidLoad] + 20 at FW_MyHomeViewController.m:58, address = 0x0000000105aec944, resolved, hit count = 2
9: file = '/Users/xxxx/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 0
9.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0
4.5 禁用/启用断点 breakpoint disable/enable
//禁用断点
(lldb) breakpoint disable 9
1 breakpoints disabled.
(lldb) breakpoint list
Current breakpoints:
9: file = '/Users/zmz/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1 Options: disabled
9.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, unresolved, hit count = 0
//启用断点
(lldb) breakpoint enable 9
1 breakpoints enabled.
(lldb) breakpoint list
Current breakpoints:
9: file = '/Users/zmz/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 0
9.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0
4.6 移除断点 breakpoint delete
(lldb) breakpoint delete 8
1 breakpoints deleted; 0 breakpoint locations disabled.
(lldb) breakpoint list
Current breakpoints:
9: file = '/Users/xxxx/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 0
9.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0
结语:
有了这些命令,调试起来肯定就得心应手了。总结下常用的,供多看几遍加深回忆:
堆栈相关:bt查看堆栈、frame select跳帧、frame variable查看帧参数、thread return跳出当前执行、【step/finish/next/continue】进入/跳出/下一步/跳出本断点
断点相关:breakpoint set -f -l -c条件断点、breakpoint set -n方法断点、breakpoint delete断点移除、breakpoint list断点列表
image命令:image lookup -address崩溃定位、image lookup -name方法来源、 image lookup –type 查看成员
LLDB支持简写
iOS之LLDB常用调试命令的更多相关文章
- gdb常用调试命令
一般来说,GDB主要帮忙你完成下面四个方面的功能: 1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序. 2.可让被调试的程序在你所指定的调置的断点处停住.(断点可以是条件表达式) ...
- GDB常用调试命令以及多进程多线程调试
http://blog.csdn.net/freeelinux/article/details/53700266 一:普通命令 1.list命令 list linenum 显示程序第l ...
- GDB常用调试命令(一)
GDB是UNIX及UNIX-like下的调试工具,通常gdb使用前置条件:编译时加入debug信息,这里指的是C++. gcc/g++调试选项 gcc/g++是在编译时加入-g,-g分4个等级: ...
- gdb常用调试命令以及多线程堆栈的查看
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC ...
- GDB常用调试命令(二)
GDB信号处理 在GDB中使用handle命令定义一个信号处理.信号可以以SIG开头或不以 SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIG ...
- puppet常用调试命令
yum快速部署puppet测试环境(C/S端) rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm yum r ...
- gdb 常用调试命令
1. file quit 2. frame bt 3. finish 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数信息. until 当要退出在一个循环体 ...
- squid常用调试命令
解压,编译,make ,make install 就不说了.从 make install 后开始.当你的 squid.conf 配置文档按照你的想法修改完以后,启动 squid 之旅就开始了.1,初始 ...
- npm和yarn常用调试命令
yarn查看全局安装路径 yarn global dir npm查看所有全局安装的包<全局路径也会显示> npm list --depth=0 -global
随机推荐
- Java的运行原理
在Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器.这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口.编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由 ...
- 用python开发调试器——起始篇
首先,你得准备一套python开发环境,正常情况下,一般是在windows下开发的,因为win系统应用广泛,再则就是要有个IDE,这里我选择我熟悉的Eclipse.环境搭建,网上都有,比如:http: ...
- Day6_正则表达式
用作匹配数据的方法: print(re.findall('\w','yangshuai 123 asd \n \t')) #w:匹配字母数字下划线 print(re.findall('\W','yan ...
- 前端Mahsup异步依赖方式不能做业务数据依赖
很久之前流行mashup方式做内容集成,之前为了IP定位的方便,引用了第三方的IP定位JS,然后根据其内容与服务器同步地址数据并写入Cookie,可是这种方式一旦,第三方的库反应缓慢时,就会出现大问题 ...
- C# SqlBulkCopy数据批量入库
准备条件:20万+数据 界面设计使用的WPF. 没有对比就没有伤害,以下是我两种方式导入数据案例. 运行 结果对比: 首先使用一般sql语句导入,因为时间原因,我就没有等待程序执行完,但是我记录了大约 ...
- .net core使用Ku.Core.Extensions.Layui实现layui表单渲染
演示网站地址:http://layui.kulend.com/项目地址:https://github.com/kulend/Ku.Core.Extensions/tree/master/Ku.Core ...
- 类的父类object的一些属性、方法
# class Test: # """文档字符串""" # name = 'scolia' # # print(Test.__doc__) ...
- SQL Server性能优化(8)堆表结构介绍
一.表结构综述 下图是SQL Server中表的组织形式(其中分区1.分区2是为了便于管理,把表进行分区,放到不同的硬盘数据文件里.默认情况下,表只有一个分区.).表在硬盘上的存放形式,有堆和B树两种 ...
- 3d轮播图——类似酷狗的轮播
说到轮播图,其实只要是跟web开发相关的无论是前端后端应该都不陌生,各种各样的轮播图,从以前的单纯的平面山水画遮盖滑动或滚动,到Jquery的animate甚至是h5+css3,各种炫酷的轮播图更是层 ...
- java序列化反序列化深入探究(转)
When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化.写一个排序算法也用不到序列化和反序列化.但是当你想要将一个对象进行持久化写入文件,或者你想 ...