现在你已经学到了两个最基本的命令apropos
和help
.是时候研究一下LLDB是如何把自己附加到进程上的.你会学习到所有用不同的选项把LLDB附加到进程上的不同方法, 以及附加到进程后会发生什么.
附加attaching
这个单词多少有点误导.一个叫debugserver
的程序(可以在Xcode.app/Contents/SharedFrameworks/LLDB.framework/ Resources/
里找到), 负责附加到目标进程上.
如果要附加的是一个远程进程, 比如是一个运行在iOS, watchOS或者tvOS的设备上的应用程序, 一个远程debugserver
会在那个远程设备上启动.启动, 连接和使用debugserver定位来处理在调试应用程序过程中所有的交互是LLDB的工作.
附加到已经存在的进程上
就像你再第一章中看到的, 你可以用下面的命令附加到一个进程上:
lldb -n Xcode
然而, 我们还有另外一种方法做这件事!你可以通过使用进程标识符或者PID将LLDB附加到正在运行的进程上.
打开Xcode, 然后打开一个新的终端窗口, 然后运行下面的命令:
pgrep -x Xcode
这条命令会输出Xcode进程的PID.
然后, 运行下面这条命令, 并把89944用上面得到的PID替换掉:
lldb -p 89944
这条指令告诉LLDB用用指定的PID附加到进程上.在这里就是Xcode的进程.
附加到一个将来的进程上
上面的命令只能附加到正在运行的进程上.如果Xcode没有运行, 上面的命令就会失效.如何在你还不知道进程PID的情况下捕获到即将启动的进程呢?
你可以使用-w
参数做到, 这会让LLDB进入等待状态直到特定PID的进程启动或者可执行文件的名字与-w
的参数一致的时候.
例如, 在终端里按下Ctrl + D
杀掉已经存在的LLDb进程, 然后输入下面的命令:
lldb -n Finder -w
这条命令会让LLDB附加到一个下次启动的名字叫Finder
的进程上. 然后打开一个新的终端窗口, 并输入一下命令:
pkill Finder
这条命令会杀掉Finder进程并强制重启Finder进程.
macOS会自动重启Finder当Finder被杀掉的时候.切换到你第一次创建的终端窗口中, 你会发现LLDB已经附加到了最近创建的Finder进程上.
另外一个附加到指定进程的方法是指定可执行文件的路径, 并在你方便的时候手动启动进程.
lldb -f /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
这会将Finder设置为可执行文件启动.一旦你准备好开始调试了, 只需在LLDB会话中简单的输入下面的命令:
(lldb) process launch
注意:一个有趣的现象是当你手动启动一个进程的时候stderr会自动发送到终端窗口. 用其他方法附加LLDB的时候不会自动做这件事.
启动时的选项
进程启动命令有一些选项值得我们进一步探索.如果你感觉好奇并且想知道启动进程时可用选项的完整列表, 只需要简单键入help process launch
.
关闭前面的LLDB会话, 打开一个新的终端窗口并且输入下面的命令:
lldb -f /bin/ls
这条命令告诉LLDB使用/bin/ls
(文件列表命令)作为可执行文件.
你会看到下面这些输出:
(lldb) target create "/bin/ls"
Current executable set to '/bin/ls' (x86_64).
鉴于ls
是一个很迅速的程序(它会启动, 完成它的工作, 然后退出),你将会用不同的参数多次运行这个程序来浏览每次都做了什么.
第一次先尝试在没有参数的情况下启动ls
. 输入下面的命令:
(lldb) process launch
你将会看到下面的输出:
Process 7681 launched: '/bin/ls' (x86_64)
... # Omitted directory listing output
Process 7681 exited with status = 0 (0x00000000)
一个ls
进程将会在你当前的工作目录里启动.你也可以用-w
选项告诉LLDB改变当前的工作目录.
输入下面的命令:
(lldb) process launch -w /Applications
这条命令会在/Applications
目录下启动ls
程序.
这条命令等价于下面这条命令:
$ cd /Applications
$ ls
我们还有另外一条方法来做到同样的事情.取而代之的是你可以告诉LLDB运行程的目录, 你可以给程序目录参数传一个值.
输入下面的命令:
(lldb) process launch -- /Applications
这条命令与之前的命令拥有同样的效果, 但是这一次他做了下面的事情:
$ ls /Applications
这一次, 会罗列出你macOS中所有的应用程序, 但是你指定了一个参数改变了ls
启动的目录.怎样将你桌面的目录作为启动参数呢?键入下面的命令:
(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
.要学习更多创建自己命令的快捷键的, 请参考第八章"Persisting and Customizing Commands".
输入下面的命令来查看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
(standard input). 这对像Xcode这样的GUI程序是非常有用的, 但是对于像ls
和wc
这样的终端命令来说没有实质性的帮助.
举例说明你一下, 不用任何参数运行wc
程序, 键入下面的内容:
(lldb) run
这个程序将只是挂在那里因为它希望从stdin
里读到一些输入.
键入hello world
来给它一些输入, 在字符的结尾处, 按下Return
, 然后按下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
没有可以处理的数据并且立即退出.
我们为什么要学习这些东西?
还有一些更有趣的选项可以用, 你会在后面的章节里看到它们.在后面的章节中, 你将会学到LLDB如何将自己附加到iOS设备的远程debugsever上.
从现在开始尝试附加到非GUI程序上就像附加到GUI程序上那样.尝试在终端中运行你期望的stdin
或者参数, 然后看看你发现了什么?
网友评论