XCode调试器LLDB

与调试器共舞 - LLDB 的华尔兹

  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值?
NSLog(@"%@", whatIsInsideThisThing);
  • 或者跳过一个函数调用来简化程序的行为?
NSNumber *n = @7; // 实际应该调用这个函数:Foo();
  • 或者短路一个逻辑检查?
if (1 || theBooleanAtStake) { ... }
  • 或者伪造一个函数实现?
int calculateTheTrickyValue {
  return 9;

  /*
   先这么着
   ...
   */
}
  • 并且每次必须重新编译,从头开始?
  • 构建软件是复杂的,并且 Bug 总会出现。一个常见的修复周期就是修改代码,编译,重新运行,并且祈祷出现最好的结果。
  • 但是不一定要这么做。你可以使用调试器。而且即使你已经知道如何使用调试器检查变量,它可以做的还有很多。
  • 这篇文章将试图挑战你对调试的认知,并详细地解释一些你可能还不了解的基本原理,然后展示一系列有趣的例子。现在就让我们开始与调试器共舞一曲华尔兹,看看最后能达到怎样的高度。

LLDB

  • LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展。(这里有一个关于调试器如何工作的总体的解释。)
  • 你以前有可能已经使用过调试器,即使只是在 Xcode 的界面上加一些断点。但是通过一些小的技巧,你就可以做一些非常酷的事情。GDB to LLDB 参考是一个非常好的调试器可用命令的总览。你也可以安装 Chisel,它是一个开源的 LLDB 插件合辑,这会使调试变得更加有趣。
  • 与此同时,让我们以在调试器中打印变量来开始我们的旅程吧

基础

  • 这里有一个简单的小程序,它会打印一个字符串。注意断点已经被加在第 8 行。断点可以通过点击 Xcode 的源码窗口的侧边槽进行创建。
  • 程序会在这一行停止运行,并且控制台会被打开,允许我们和调试器交互。那我们应该打些什么呢?

help

  • 最简单命令是 help,它会列举出所有的命令。如果你忘记了一个命令是做什么的,或者想知道更多的话,你可以通过 help command 来了解更多细节,例如 help print 或者 help thread。如果你甚至忘记了 help 命令是做什么的,你可以试试 help help。不过你如果知道这么做,那就说明你大概还没有忘光这个命令。

print

  • 打印值很简单;只要试试 print 命令:
  • LLDB 实际上会作前缀匹配。所以你也可以使用 prin,pri,或者 p。但你不能使用 pr,因为 LLDB 不能消除和 process 的歧义 (幸运的是 p 并没有歧义)。
  • 你可能还注意到了,结果中有个 $0。实际上你可以使用它来指向这个结果。试试 print $0 + 7,你会看到 106。任何以美元符开头的东西都是存在于 LLDB 的命名空间的,它们是为了帮助你进行调试而存在的。

expression

  • 如果想改变一个值怎么办?你或许会猜 modify。其实这时候我们要用到的是 expression 这个方便的命令。
  • 这不仅会改变调试器中的值,实际上它改变了程序中的值。这时候继续执行程序,将会打印 42 red balloons。神奇吧。
  • 注意,从现在开始,我们将会偷懒分别以 p 和 e 来代替 print 和 expression。

什么是 print 命令

  • 考虑一个有意思的表达式:p count = 18。如果我们运行这条命令,然后打印 count 的内容。我们将看到它的结果与 expression count = 18 一样。和 expression 不同的是,print 命令不需要参数。比如 e -h +17 中,你很难区分到底是以 -h 为标识,仅仅执行 +17 呢,还是要计算 17 和 h 的差值。连字符号确实很让人困惑,你或许得不到自己想要的结果。
  • 幸运的是,解决方案很简单。用 -- 来表征标识的结束,以及输入的开始。如果想要 -h 作为标识,就用 e -h -- +17,如果想计算它们的差值,就使用 e -- -h +17。因为一般来说不使用标识的情况比较多,所以 e -- 就有了一个简写的方式,那就是 print。
  • 输入 help print,然后向下滚动,你会发现:
'print' is an abbreviation for 'expression --'.
(print是 `expression --` 的缩写)

打印对象

  • 尝试输入
p objects
  • 输出会有点啰嗦
(NSString *) $7 = 0x0000000104da4040 @"red balloons"
  • 如果我们尝试打印结构更复杂的对象,结果甚至会更糟
(lldb) p @[ @"foo", @"bar" ]

(NSArray *) $8 = 0x00007fdb9b71b3e0 @"2 objects" 
  • 实际上,我们想看的是对象的 description 方法的结果。我么需要使用 -O (字母 O,而不是数字 0) 标志告诉 expression 命令以 对象 (Object) 的方式来打印结果。
(lldb) e -O -- $8
<__NSArrayI 0x7fdb9b71b3e0>(
    foo,
    bar
)
  • 幸运的是,e -o -- 有也有个别名,那就是 po (print object 的缩写),我们可以使用它来进行简化:
(lldb) po $8
<__NSArrayI 0x7fdb9b71b3e0>(
    foo,
    bar
)
(lldb) po @"lunar"
lunar
(lldb) p @"lunar"
(NSString *) $13 = 0x00007fdb9d0003b0 @"lunar"

变量

  • 现在你已经可以打印对象和简单类型,并且知道如何使用 expression 命令在调试器中修改它们了。现在让我们使用一些变量来减少输入量。就像你可以在 C 语言中用 int a = 0 来声明一个变量一样,你也可以在 LLDB 中做同样的事情。不过为了能使用声明的变量,变量必须以美元符开头。
(lldb) e int $a = 2
(lldb) p $a * 19
38
(lldb) e NSArray *$array = @[ @"Saturday", @"Sunday", @"Monday" ]
(lldb) p [$array count]
2
(lldb) po [[$array objectAtIndex:0] uppercaseString]
SATURDAY
(lldb) p [[$array objectAtIndex:$a] characterAtIndex:0]
error: no known method '-characterAtIndex:'; cast the message send to the method's return type
error: 1 errors parsing expression
// 悲剧了,LLDB 无法确定涉及的类型 (译者注:返回的类型)。这种事情常常发生,给个说明就好了:

(lldb) p (char)[[$array objectAtIndex:$a] characterAtIndex:0]
'M'
(lldb) p/d (char)[[$array objectAtIndex:$a] characterAtIndex:0]
77

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Restful Objects for .NET

Restful Objects是关于领域对象模型的超媒体API的公共规范。该规范的1.0.0 版本刚刚发布并提供下载,并且目前已经出现了两个实现了该规范的开源框...

17280
来自专栏互扯程序

Java 9 逆天的十大新特性

KS Knowledge Sharing 知识分享 现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。 在介绍...

27260
来自专栏企鹅号快讯

Java 9 逆天的十大新特性

在介绍 Java 9 之前,我们先来看看 Java 成立到现在的所有版本。 1990 年初,最初被命名为 Oak; 1995 年 5 月 23 日,Java 语...

24750
来自专栏JavaEdge

控制并发线程数的Semaphore信号量(Semaphore)语法应用场景其他方法

44970
来自专栏HansBug's Lab

【技巧】Java工程中的Debug信息分级输出接口及部署模式

UPDATE: 2018.4.4 笔者将考虑将这一模块封装成一个完整的java第三方包并可能进行开源放送,完成后将会再次发布最新消息,敬请期待。 -------...

42660
来自专栏C/C++基础

jsoncpp初探

首先说一下JSON。JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 JSO...

19120
来自专栏Hongten

JSP 六讲

15920
来自专栏osc同步分享-java技术分享站

在springBoot项目中使用activiti

http://www.jvm123.com/2019/08/springboot-activiti/

3.8K70
来自专栏机器学习从入门到成神

Java 进阶面试问题列表

12010
来自专栏程序猿DD

探讨通过Feign配合Hystrix进行调用时异常的处理

作者:任聪 原文:http://www.jianshu.com/p/f240ca7bb7c0 前言:此文所述处理方式为本人在实践过程中研究分析得出的一种解决方案...

53050

扫码关注云+社区

领取腾讯云代金券