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下的断点还给提示所有断到的位置。

viewDidLoad断点
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 

5 别名

其实很多命令是LLDB一些命令的别名,比如p是frame variable的别名,p view实际上是frame variable view。除了系统自建的LLDB别名,你也可以自定义别名。

5.1 自定义别名 command alias

很多时候,LLDB完整的命令是很长的。比如前面所说的image lookup --address这个组合命令。为了方便日常的使用,提高效率,LLDB命令也提供通过简称的方式调用命令。
为了说明问题,我来个奇葩的,中文定义!!!

(lldb) command alias 查看堆栈 thread backtrace
(lldb) 查看堆栈 5
  thread #5
    frame #0: 0x000000010bd3544e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010bd69621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010bd6907d libsystem_pthread.dylib`start_wqthread + 13

5.2 带参数别名 command alias %1 %2等等

(lldb) command alias 删除断点 breakpoint delete %1
(lldb) breakpoint list
Current breakpoints:
3: file = 'JSONKit.m', line = 725, exact_match = 0, locations = 1, resolved = 1, hit count = 0
  3.1: where = TEST`-[JKArray dealloc] + 20 at JSONKit.m:727, address = 0x00000001073360c4, resolved, hit count = 0 
(lldb) 删除断点 3
1 breakpoints deleted; 0 breakpoint locations disabled.

虽然我用了中文命名,但不要学习我哦,这里只是为了说明命名不只支持英文的问题。
而且,命名尽量符合简写规律,这样更有利于使用。如help command alias中给出的例子:

(lldb) command alias bpl breakpoint list
(lldb) command alias bfl breakpoint set -f %1 -l %2

5.3 持久存储

我们在xcode下打command alias,在下次项目运行时直接就没了,有个办法可以做到持久存储。lldb初始化时会读取~/.lldbinit文件,我们可以把简写命令写进此文件中。

添加步骤:
  1. 打开终端,输入vi ~/.lldbinit进入文件编辑。
  2. 写入自定义内容,如:command alias 堆栈 thread backtrace
  3. 然后ESC键,出现冒号后输入wqenter键保存并退出编辑。

Xcode中断点使用

xcode中断点其实是对lldb的一个界面化,确实使用起来特别方便。
但有一点不同:使用lldb添加的断点,下次运行时就失效了,而xcode中设置的断点仍然正常使用

示例

1. 条件断点
条件断点
2. 添加断点事件

我们项目中就有一个使用场景:用户想要发贴,会先请求一个接口,返回用户是否有发帖权限。有权限跳转发帖页,无权限跳转无权限提示页。所以我们在debug的时候,就会在返回值isHasPermisson那里添加一个断点,action中把值改为1,勾选自动继续。如下图:

image.png

执行结果:

image.png

通过添加断点,可以做到偷偷改动断点处的一个参数值,避免修改代码,或者频繁手动exp修改值,简直是方便。

结语:

有了这些命令,调试起来肯定就得心应手了。总结下常用的,供多看几遍加深回忆:

堆栈相关: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支持简写

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容

  • LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xc...
    CoderSC阅读 1,346评论 0 2
  • [转]浅谈LLDB调试器文章来源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc阅读 2,484评论 2 6
  • LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xc...
    小笨狼阅读 20,432评论 31 187
  • 随着Xcode 5的发布,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器。它与LLVM编译器一...
    随风飘荡的小逗逼阅读 1,398评论 0 0
  • 古典美女,当我第一次看到这样照片时候,不管从她的打扮,还她的衣服色彩,非常好看非常美,但是过了很久我才开始画这幅画...
    烨然v阅读 369评论 0 2