第三章:使用 LLDB 连接

既然你已经了解了两个最重要的命令,help 和 apropos,现在是时候研究 LLDB 如何连接进程。 你将学习使用各种选项将 LLDB 连接到进程的所有方式,以及连接到进程后发生的结果。

LLDB “连接”这个词实际上有点误导。 名为 debugserver 的程序(在 Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/ 中找到)负责连接到目标进程。

如果它是一个远程进程,例如运行在远程设备上的 iOS,watchOS 或 tvOS 应用程序,远程的 debugserver 将在该远程设备上启动。 LLDB 的工作是启动,连接和协调 debugserver,以处理调试应用程序中的所有交互。

连接到已有进程

正如你在第一章中已经看到的那样,你可以像这样连接一个进程:

lldb -n Xcode

然而,还有其他方法可以做同样的事情。 你可以通过提供正在运行的程序的进程标识符或 PID 来连接到 Xcode。

打开 Xcode,然后打开一个新的终端会话,最后运行以下内容:

pgrep -x Xcode

这会输出 Xcode 进程的 PID。

接下来,运行以下命令,用上面的命令替换 89944 的数字输出:

lldb -p 89944

这让 LLDB 使用给定的 PID 连接到进程。 目前,连接的是你正在运行的 Xcode 进程。

连接到未来进程

之前的命令只能获取正在运行的进程地址。 如果 Xcode 没有运行,或者已经连接到调试器,那么之前的命令将会失败。 如果你还不知道 PID,你怎么能得到一个即将启动的进程呢?

你可以用 -w 参数来做到这一点,这会导致 LLDB 等待一个进程启动,其 PID 或可执行进程名称与使用 -p 或 -n 参数提供的条件匹配。

例如,通过在终端窗口中按 Ctrl + D 来终止现有的 LLDB 会话,然后输入以下内容:

lldb -n Finder -w

这会让 LLDB 在下次启动时连接名为 Finder 的进程。 接下来,打开一个新的终端选项卡,并输入以下内容:

pkill Finder

这将终止 Finder 进程并强制重启。 终止后,macOS 会自动重新启动 Finder。 切换回你的第一个终端选项卡,你会注意到 LLDB 已经把自己连接到新创建的 Finder 进程中。

另一种连接到进程的方法是指定可执行进程的路径,并在方便时手动启动进程:

lldb -f /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder

这将设置 Finder 作为可执行进程启动。 一旦准备好开始调试会话,只需在 LLDB 会话中输入以下内容:

(lldb) process launch

注意:一个有趣的副作用是,手动启动进程时,stderr 输出(即 NSLog 和公司)会自动发送到终端窗口。 其他 LLDB 连接配置不会自动执行此操作。

启动时的选项

process launch 命令带有一套值得进一步探索的选项。 如果你好奇,想要查看 process launch 的可用选项的完整列表,只需输入 help process launch。

关闭之前的 LLDB 会话,打开一个新的终端窗口并输入以下内容:

lldb -f /bin/ls

这告诉 LLDB 使用 /bin/ls(文件列表命令)作为目标可执行进程。

注意:如果你省略了-f选项,LLDB 会自动推断第一个参数作为可执行进程来启动和调试。 在调试终端可执行进程时,我经常输入 lldb $(which ls)(或其他等价内容),然后转换成 lldb /bin/ls。

你会看到下面的输出:

(lldb) target create "/bin/ls"
Current executable set to '/bin/ls' (x86_64).

由于 ls 是一个快速的程序(它启动,完成工作,然后退出),你将用不同的参数多次运行这个程序来探索每一个的作用。

不带参数从 LLDB 启动 ls。 输入以下内容:

(lldb) process launch

你会看到下面的输出:

Process 7681 launched: '/bin/ls' (x86_64)
... # Omitted directory listing output
Process 7681 exited with status = 0 (0x00000000)

一个 ls 进程将在你最初的目录中启动。您可以通过告诉 LLDB 在哪里启动 -w 选项来更改当前的工作目录。 输入以下内容:

(lldb) process launch -w /Applications

这将从 /Applications 目录中启动 ls。 这等价于以下内容:

$ cd /Applications
$ ls

还有另一种方式来做到这一点。 不要让 LLDB 改变目录然后运行程序,你可以直接将参数传递给程序。

(lldb) process launch -- /Applications

这和前面的命令有相同的效果,但是这一次是这样做的:

$ ls /Applications

再说一次,这列出了所有的 macOS 程序,但是你指定了一个参数而不是改变起始目录。 将桌面目录指定为启动参数怎么样? 尝试运行这个:

(lldb) process launch -- ~/Desktop

你会看到下面的输出:

Process 8103 launched: '/bin/ls' (x86_64)
ls: ~/Desktop: No such file or directory
Process 8103 exited with status = 1 (0x00000001)

噢,没有生效。 你需要 shell 来扩展参数中的波浪号。 试试这个:

(lldb) process launch -X true -- ~/Desktop

-X 选项扩展你提供的任何 shell 参数,例如波浪号。 在 LLDB 中有一个快捷方式:只需输入 run 即可。 要了解有关创建自定义命令快捷键的更多信息,请查看第八章“持久化和自定义命令”。

输入以下内容以查看 run 的文档:

(lldb) help run

你会看到下面的输出:

...
Command Options Usage:
  run [<run-args>]


'run' is an abbreviation for 'process launch -X true --'

看到了吗? 这是你刚才跑的命令的缩写! 通过输入以下内容来执行命令:

(lldb) run ~/Desktop

将控制台输出更改到不同的位置会怎么样? 你已经在第一章中尝试使用 -e 标志将 stderr 更改为其他终端选项卡,但 stdout 会怎么样呢?

输入以下内容:

(lldb) process launch -o /tmp/ls_output.txt -- /Applications

-o 选项告诉 LLDB 将 stdout 传到给定的文件。

你会看到下面的输出:

Process 15194 launched: '/bin/ls' (x86_64)
Process 15194 exited with status = 0 (0x00000000) 

注意,没有直接从 ls 输出。

打开另一个终端选项卡,然后运行以下命令:

cat /tmp/ls_output.txt

你的应用程序目录应该再次输出,如预期结果一样!

stdin 也有一个选项 -i。 首先,输入以下内容:

(lldb) target delete

这将消除 ls 作为目标。 接下来,输入这个:

(lldb) target create /usr/bin/wc

这将 /usr/ bin/wc 设置为新目标。 wc 可以用来计算给 stdin 输入的字符,单词或者行数。

你已经把你的 LLDB 会话的目标可执行进程从 ls 换成了 wc。 现在你需要提供一些数据给 wc。 打开一个新的终端选项卡并输入以下内容:

echo "hello world" > /tmp/wc_input.txt

你会用这个文件给 wc 一些输入。

切换回 LLDB 会话并输入以下内容:

(lldb) process launch -i /tmp/wc_input.txt

你会看到下面的输出:

Process 24511 launched: '/usr/bin/wc' (x86_64)
       1       2      12
Process 24511 exited with status = 0 (0x00000000) 

这在功能上等同于以下内容:

$ wc < /tmp/wc_input.txt

有时候你不需要 stdin(标准输入)。 这对于 Xcode 等 GUI 程序非常有用,但对于终端命令(如 ls 和 wc)没什么帮助。

为了举例说明,不带任何参数运行 wc 目标,就像这样:

(lldb) run

程序只是等待着,因为它期望从 stdin 读取一些东西。

给它输入 hello world,按回车键,然后按 Control + D,这是传输字符的结尾。 wc 将解析输入并退出。 你将看到与作为输入的使用文件相同的输出。

现在,像这样启动过程:

(lldb) process launch -n

你会看到 wc 立即退出,输出如下:

Process 28849 launched: '/usr/bin/wc' (x86_64)
Process 28849 exited with status = 0 (0x00000000)

-n 选项告诉 LLDB 不要创建 stdin,wc 没有数据可以处理,因此退出。

接下来?

还有一些有趣的选项可以使用(你可以通过 help 命令找到),你需要自己花时间去探索。

现在,尝试连接到 GUI 和非 GUI 程序。 如果没有源代码,你可能理解不了太多的东西,但是在即将到来的章节中你会发现在这些程序中你能得到多少信息和控制。

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

推荐阅读更多精彩内容