和 LLDB 调试器来一场说跳就跳的华尔兹(一)

序:原文 Dancing in the Debugger — A Waltz with LLDB
声明:译文有一部分参考自:与调试器共舞 - LLDB 的华尔兹


前言

你是否曾经为试图理解尼的代码和打印一个变量的值而感到苦恼?

NSLog(@"%@", whatIsInsideThisThing);

或者跳过一个函数调用来简化程序的行为?

NSNumber *n = @7; // theFunctionThatShouldReallyBeCalled();

或短路一个逻辑检查?

if (1 || theBooleanAtStake) { ... }

抑或伪造一个函数的实现?

int calculateTheTrickyValue {
  return 9;

  /*
   Figure this out later.
   ...
}

并且每次都必须重新编译,重新运行吗?

构建软件是复杂的,并且bug总是会出现。常见的修复周期是修改代码,编译,再次运行,并希望变的最好。

其实并不需要这样。您可以使用调试器哈!即使你已经知道如何使用调试器来检查一个变量,可是调试器可以做的远不止这些。

本文打算挑战你对调试的认知,更详细地解释了一些你可能不知道的基本原理,然后给你展示一些有趣的例子。让我们随着舞曲开始旋转起来,看看我们会以何种水平结束。

LLDB

LLDB 是一个有着 REPL 特性,并内置 C++Python 插件的开源调试器。该调试器捆绑在Xcode内部,并内置于Xcode窗口底部的控制台面板里。调试器允许您在程序运行的特定时刻暂停程序,来检查变量的值,执行自定义的指令,然后按照你所认为合适的步骤来操作程序的进展。(这里 是调试器如何工作的大体介绍。)

之前尼很有可能使用过调试器,即使只是在Xcode窗口页面添加断点。但是有一些小窍门,可以使你有一些很漂亮而又酷爽的事情去做。GDB to LLDB 参考的是一个伟大的可用命令的鸟瞰图,你还有可能想要安装 Chisel ,一个可以使调试器更加有趣的 LLDB 插件的开源合辑。

与此同时,让我们以 在调试器中如何打印一个变量的值 来开始这场华尔兹的旅程吧。

基础知识

这里是一段打印一个字符串的简单示例小程序。注意,在第16行添加了一个断点:

断点的示例小程序

程序会在第16行被暂停运行,并且控制台会被打开,允许我们和调试器交互。那我们应该输入些什么呢?

help

最简单的命令是 help ,这一指令将会列出所有的命令。如果你忘记某条命令是做什么的或者想了解更多的命令,你可以使用 help 命令查看更多的细节,例如 help printhelp thread 。如果你忘记了 help 命令是做什么的?你可以使用 help help 命令,但如果你知道的足够多,也许你还没有完全忘记命令是做什么的。

print

使用 print 命令打印一个值是很简单的。

print 的使用

LLDB 实际上会做前缀匹配,因此尼也可以使用 prinprip 命令,但是不可以使用 pr ,因为 LLDB 不能把它和 process 命令做区分(幸运的是,p 并没有歧义)。
你可能还会注意到,结果中有个 $0。实际上你可以使用它来代指这个结果。试试 print $0 + 7,你会看到 45。任何以美元符开头的东西都是存在于 LLDB 的命名空间的,它们是为了帮助你进行调试而存在的。

expression

如果想修改一个值怎么办?这里使用 expression 命令。

expression

这一命令不仅仅修改了调试器中的值,实际上还修改了程序中的值。如果你在这个基础上继续执行程序,将会打印83 huang qimeng,神奇吧!
从现在开始,我们下面会使用这两个命令的简化形式 pe

什么是 print 命令

这里有一个有趣的表达式:p count = 18,如果我们执行这个命令并打印count的值,我们会看到结果和这个表达式 expression count = 18 是一个吊样的。

expression不同的是,print不需要参数,比如e -h +17到底是以-h为标识,仅仅执行+17呢,还是计算17h的差值呢?连字符确实让人困惑,你可能得不到尼想要的结果。

幸运的是解决方式很简单,使用--表示标识的结束,和输入的开始,比如以-h作为标识,就要用e -h -- +17,如果想计算它们的差值,就使用e -- -h +17,一般来说,不使用标识的情况比较普遍,所以e --就有了一个简写的方式,即print

输入help print,然后向下滚动,就会发现:

'print' is an abbreviation for 'expression --'.
(print是 `expression --` 的简写)

打印对象

输入:

p objects

然后输出是一堆奇怪的东西:

(NSString *) $7 = 0x0000000104da4040 @"huang qimeng"

如果我们尝试打印结构更复杂的对象,结果甚至会更糟:

(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 --也有个别名,即poprint object的缩写),我们可以这样使用:

(lldb) po $8
<__NSArrayI 0x7fdb9b71b3e0>(
foo,
bar
)
(lldb) po @"lunar"
lunar
(lldb) p @"lunar"
(NSString *) $13 = 0x00007fdb9d0003b0 @"lunar"

打印变量

可以为print指定不同的打印格式。他们都以print/<fmt>或者简化的p/<fmt>格式书写。例子如下:
默认格式:

(lldb) p 16
16

十六进制:

(lldb) p/x 16
0x10

二进制(t代表two):

(lldb) p/t 16
0b00000000000000000000000000010000
(lldb) p/t (char)16
0b00010000

你也可以使用p/c打印字符,或者p/s打印以空终止的字符串*char **,这里是输出格式的完整说明。

变量

现在你已经可以打印对象和简单类型的变量了,以及如何使用expression命令在调试器中修改他们了。~~此处废话不翻译~~,不过为了能使用声明的变量,变量必须以美元符号$开头。

(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

变量使调试器的使用变得更容易了,你想不到吧?😄

未完待续...

移步 和 LLDB 调试器来一场说跳就跳的华尔兹(二)

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

推荐阅读更多精彩内容