iOS调试工具LLDB(转)

原文地址: http://www.jianshu.com/p/e30caeba3dc0

开发iOS的时候常常会用到调试跟踪,如何正确的使用调试器来debug十分重要。Xcode里有内置的Debugger,老版使用的是GDB,Xcode自4.3之后默认使用的就是LLDB了。
GDB: UNIX及UNIX-like下的调试工具。
LLDB: 开源的内置于XCode的具有REPL(read-eval-print-loop)特征的Debugger,其可以安装C++或者Python插件。

两个都是调试用的Debugger,只是LLDB是比较高级的版本,或者在调试开发iOS应用时比较好用,lldb与gdb命令名的对照表:http://lldb.llvm.org/lldb-gdb.html
开始使用LLDB
在什么地方可以输入这个命令?首先, 在程序里你需要的地方设置断点。当断点断住的时候你就能看到我们进入LLDB调试器了。


这时就可以使用一些LLDB命令来进行一些调试了。
一些Xcode调试快捷键:command+shift+Y 打开调试窗口command+Y 调试运行程序command+option+P 继续command+shift+O 跳过command+shift+I 进入command+shift+T 跳出

常用命令
help
最简单命令 help 会列举出所有的命令。如果你忘记了一个命令是做什么的,或者想知道更多的话,你可以通过 help <command> 来了解更多细节,例如 help print 或者 help thread。




print
试试 print 命令:



LLDB 实际上会作前缀匹配。所以你也可以使用 prin,pri,或者 p。但你不能使用 pr,因为 LLDB 不能消除和 process 的歧义。
结果中有个 $0。实际上你可以使用它来指向这个结果。试试 print $0 + 7,你会看到 106。任何以美元符开头的东西都是存在于 LLDB 的命名空间的,它们是为了帮助你进行调试而存在的。
输出view 下 subview 的数量
//由于 subview 的数量是一个 int 类型的值,所以我们使用命令p:(lldb)p (int)[[[self view] subviews] count]

直接调用方法改变背景颜色之类
其实使用p,po,call都可以调用方法,只是p和po都是用于输出的有返回值的。call一般只在不需要显示输出,或是方法无返回值时使用。(lldb)p [self.view setBackgroundColor:[UIColor redColor]](lldb)p (void)[CATransaction flush]上述的p一般使用call比较好,因为方法是没有返回值的。

p objects
命令p objects跟p很像。p输出的是基本类型,po输出的Objective-C对象。调试器会输出这个 object 的 description。po (print object 的缩写):



expression
如果想改变一个值怎么办?其实这时候我们要用到的是 expression 这个方便的命令。expression的简写就是e。可以用expression来声明新的变量,也可以改变已有变量的值。我们看到e声明的都是$开头的变量。我们在使用时也需要加上$符号。
创建新的变量示例:



注意:如果上面这里输入以下命令,会发生错误。说明lldb无法判定某一步的计算结果是什么数据类型,这时需要强制类型转换来告诉lldb。
(lldb) p [[$array objectAtIndex:0] characterAtIndex:0]error: no known method '-characterAtIndex:'; cast the message send to the method's return typeerror: 1 errors parsing expression(lldb) p (char)[[$array objectAtIndex:0] characterAtIndex:0]'o'

修改已有变量示例:



image
image 命令可用于寻址,有多个组合命令。比较实用的用法是用于寻找栈地址对应的代码位置。如:
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];NSLog(@"%@",arr[2]);

这段代码有明显的错误,程序运行这段代码后会抛出下面的异常:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'*** First throw call stack:( 0 CoreFoundation 0x0000000101951495 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x00000001016b099e objc_exception_throw + 432 CoreFoundation 0x0000000101909e3f -[__NSArrayI objectAtIndex:] + 1753 ControlStyleDemo 0x0000000100004af8 -[RootViewController viewDidLoad] + 3124 UIKit 0x000000010035359e -[UIViewController loadViewIfRequired] + 5625 UIKit 0x0000000100353777 -[UIViewController view] + 296 UIKit 0x000000010029396b -[UIWindow addRootViewControllerViewIfPossible] + 587 UIKit 0x0000000100293c70 -[UIWindow _setHidden:forced:] + 2828 UIKit 0x000000010029cffa -[UIWindow makeKeyAndVisible] + 519 ControlStyleDemo 0x00000001000045e0 -[AppDelegate application:didFinishLaunchingWithOptions:] + 67210 UIKit 0x00000001002583d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 26411 UIKit 0x0000000100258be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 160512 UIKit 0x000000010025ca0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 66013 UIKit 0x000000010026dd4c -[UIApplication handleEvent:withNewEvent:] + 318914 UIKit 0x000000010026e216 -[UIApplication sendEvent:] + 7915 UIKit 0x000000010025e086 _UIApplicationHandleEvent + 57816 GraphicsServices 0x0000000103aca71a _PurpleEventCallback + 76217 GraphicsServices 0x0000000103aca1e1 PurpleEventCallback + 3518 CoreFoundation 0x00000001018d3679 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION + 4119 CoreFoundation 0x00000001018d344e __CFRunLoopDoSource1 + 47820 CoreFoundation 0x00000001018fc903 __CFRunLoopRun + 193921 CoreFoundation 0x00000001018fbd83 CFRunLoopRunSpecific + 46722 UIKit 0x000000010025c2e1 -[UIApplication _run] + 60923 UIKit 0x000000010025de33 UIApplicationMain + 101024 ControlStyleDemo 0x0000000100006b73 main + 11525 libdyld.dylib 0x0000000101fe95fd start + 126 ??? 0x0000000000000001 0x0 + 1)libc++abi.dylib: terminating with uncaught exception of type NSException

现在,我们怀疑出错的地址是0x0000000100004af8(可以根据执行文件名判断,或者最小的栈地址)。为了进一步精确定位,我们可以输入以下的命令:
(lldb)image lookup --address 0x0000000100004af8(lldb)im loo -a 0x0000000100004af8

命令执行后返回:
Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)Summary: ControlStyleDemo`-[RootViewController viewDidLoad] + 312 at RootViewController.m:53

可以看到,出错的位置是RootViewController.m
的第53行。
call
call即是调用的意思。其实上述的po和p也有调用的功能。因此一般只在不需要显示输出,或是方法无返回值时使用call。和上面的命令一样,我们在viewDidLoad:里面设置断点,然后在程序中断的时候输入下面的命令:
call [self.view setBackgroundColor:[UIColor redColor]]

继续运行程序,看看view的背景颜色是不是变成红色的了!在调试的时候灵活运用call命令可以起到事半功倍的作用。
bt
打印调用堆栈,加all可打印所有thread的堆栈。
流程控制命令
实际上使用xcode自带的可视化工具来控制“继续”“暂停”“下一步”“进入”“跳出”更简单,但这里还是列出其所对应的命令名:
继续:process continue, continue, c
下一步:thread step-over, next, n
进入:thread step-in, step, s
跳出:thread step-out, finish, f

thread return
执行thread return命令可以使得当前函数立即返回,也就是说,后续代码都不会执行了。当然执行此命令可能会使得arc的计数追踪出现错乱。
thread return命令需要一个参数来指明函数强制返回时的返回值。

断点命令
断点有很多进阶使用方法:条件断点、条件执行、记录日志、自动继续、重复断点跳过。使用xcode提供的可视化工具来操作是很容易的:



调试中执行任意代码
(lldb) e char *$str = (char *)malloc(128)(lldb) e (void)strcpy($str, "wxrld of warcraft")(lldb) e $str[1] = 'o'(char) $0 = 'o'(lldb) p $str(char *) $str = 0x00007fd04a900040 "world of warcraft"(lldb) e (void)free($str)

所以,在debugger中可以修改view的颜色、尺寸、甚至创建controller来push。
watchpoint
watchpoint可以在某个变量被写入/读取时暂停程序运行:
(lldb) watchpoint set expression -- (int*)&_abc4Watchpoint created: Watchpoint 7: addr = 0x15e36d3c size = 4 state = enabled type = w new value: 0x00000000(lldb) watchpoint set v -w read _abc4Watchpoint created: Watchpoint 8: addr = 0x15e36d3c size = 4 state = enabled type = r watchpoint spec = '_abc4' new value: 0(lldb) watchpoint set v -w read_write _abc3Watchpoint created: Watchpoint 9: addr = 0x15e36d38 size = 4 state = enabled type = rw watchpoint spec = '_abc3' new value: 0

实际上可以使用watchpoint来监视任意一段内存的读写。使用XCode也可以方便地创建watchpoint。
XCode的可视化debug工具中的watch是一个write类型watchpoint(也就是默认的)

另外,上述语句中 v是variable的简写,同样的,set可以简写为s,watch可以简写为wa,而-w后面的参数是不可以简写的必须为read、write或者read_write。
当前在arm和x86上,我们一次最多创建4个watchpoint,继续创建会提示错误。

查看内存
使用XCode的可视化工具来查看memory,要注意watch memory of "p" 和watch memory of "*p"的区别。
手动执行命令可以help x或者 help memory。

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

推荐阅读更多精彩内容

  • LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xc...
    CoderSC阅读 1,334评论 0 2
  • 转载 与调试器共舞 - LLDB 的华尔兹: https://objccn.io/issue-19-2/ 推荐:i...
    F麦子阅读 3,321评论 0 10
  • [转]浅谈LLDB调试器文章来源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc阅读 2,463评论 2 6
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    木易林1阅读 952评论 0 4
  • 见到你的时候 你就一直呆痴着,或卧床不起,或躺在沙发里 病非病,梦非梦着 你就像一直偷懒的小猫 时常等待机遇的到来...
    乔玉儿阅读 325评论 1 6