1、基本概念

动态调试就是将程序运行起来,通过下断点、打印等方式,查看参数、返回值、函数调用流程等。

2、Xcode的动态调试原理

Xcode通过LLDB连接iPhone上的debugserver,debugserver连接iPhone上的App,从而实现了App的调试,如下图所示:
image.png
debugserver一开始存放在Mac的Xcode里面:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/15.5/DeveloperDiskImage.dmg/usr/bin/debugserver
当Xcode识别到手机设备时,Xcode会自动将debugserver安装到iPhone上:
/Developer/usr/bin/debugserver
Xcode调试有一定局限性:一般情况下,只能调试Xcode安装的App。

3、动态调试任意App

3.1、调试原理

如果想要调试任意安装在iPhone上的App,就不能通过Xode启动LLDB调试器了,而需要使用终端来启动,如下图所示:
image.png

在通过Xcode调试App时,Xcode会自动打通LLDB和debugserver之间、debugserver和App之间的连接,不使用Xcode情况下,就需要手动打通这些连接。

3.2、debugserver环境搭建

3.2.1、debugserver的权限问题

默认情况下,/Developer/usr/bin目录下的debugserver缺少一定的权限,只能调试通过Xcode安装的App,无法调试其它APP(比如来自App Store的App)。如果希望调试其它App,需要对debugserver重新签名,签上两个调试相关的权限:get-task-allowtask_for_pid-allow,并删除com.apple.security.network.servercom.apple.security.network.clientseatbelt-profiles这三个权限。
iPhone上的/Developer目录时只读的,无法直接对debugserver文件进行签名,需要先把debugserver复制到Mac上,再通过ldid工具进行签名,先导出以前的签名:
$ ldid -e debugserver > debugserver.entitlements
2.png

这里的debugserver文件是iOS 14.3系统的,iOS 14.7.1系统的debugserver无法导出权限信息

整理 debugserver.entitlements 中的权限:
image.png
再通过ldid重新签名:
$ ldid -Sdebugserver.entitlements debugserver
将已经签好权限的debugserver放到iPhone的/usr/bin目录,便于找到debugserver指令。

可能提示权限不足(Permission denied),需要给debugserver添加权限:$ chmod +x /usr/bin/debugserver

3.3.2、让debugserver附加到某个App进程

$ debugserver localhost:端口号 -a 进程

localhost:端口号:使用iPhone的某个端口启动debugserver服务(只要不是保留端口号就行) -a进程:输入App的进程信息(进程ID或者进程名称) 也可以使用 $ debugserver *:端口号 -a 进程 命令,但在lldb连接debugserver时可能报错 error: failed to get reply to handshake packet

以微信为例:
$ debugserver localhost:10011 -a WeChat

  1. debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1200.2.12
  2. for arm64.
  3. Attaching to process WeChat...
  4. Listening to port 10011 for a connection from localhost...

3.3、lldb连接debugserver

在Mac上启动LLDB,远程连接iPhone上的debugserver服务,启动LLDB
$ LLDB
连接debugserver服务命令:
(lldb) process connect connect://手机IP地址:debugserver服务端口号
之前在做 USB-SSH登录 时已经把Mac的10010端口映射到了iPhone的22端口,这里可以先把Mac的10011端口映射到iPhone的10011端口debug_usb.sh,再连接debugserver:
(lldb) process connect connect://localhost:10011

  1. Process 5012 stopped
  2. * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  3. frame #0: 0x00000001cb2c5908 libsystem_kernel.dylib`mach_msg_trap + 8
  4. libsystem_kernel.dylib`mach_msg_trap:
  5. -> 0x1cb2c5908 <+8>: ret
  6. libsystem_kernel.dylib`mach_msg_overwrite_trap:
  7. 0x1cb2c590c <+0>: mov x16, #-0x20
  8. 0x1cb2c5910 <+4>: svc #0x80
  9. 0x1cb2c5914 <+8>: ret
  10. Target 0: (WeChat) stopped.

连接debugserver后,需要使用LLDB的c命令让程序继续运行:
(lldb) c
接下来就可以使用LLDB命令调试App了。
通过debugserver启动App:
$ debugserver -x auto *:端口号 App可执行文件路径