1、基本概念
动态调试就是将程序运行起来,通过下断点、打印等方式,查看参数、返回值、函数调用流程等。
2、Xcode的动态调试原理
Xcode通过LLDB连接iPhone上的debugserver,debugserver连接iPhone上的App,从而实现了App的调试,如下图所示:
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调试器了,而需要使用终端来启动,如下图所示:
在通过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-allow
、task_for_pid-allow
,并删除com.apple.security.network.server
、com.apple.security.network.client
、seatbelt-profiles
这三个权限。
iPhone上的/Developer目录时只读的,无法直接对debugserver文件进行签名,需要先把debugserver复制到Mac上,再通过ldid工具进行签名,先导出以前的签名:
$ ldid -e debugserver > debugserver.entitlements
这里的debugserver文件是iOS 14.3系统的,iOS 14.7.1系统的debugserver无法导出权限信息
整理 debugserver.entitlements 中的权限:
再通过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
debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1200.2.12
for arm64.
Attaching to process WeChat...
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
Process 5012 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00000001cb2c5908 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
-> 0x1cb2c5908 <+8>: ret
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x1cb2c590c <+0>: mov x16, #-0x20
0x1cb2c5910 <+4>: svc #0x80
0x1cb2c5914 <+8>: ret
Target 0: (WeChat) stopped.
连接debugserver后,需要使用LLDB的c命令让程序继续运行:
(lldb) c
接下来就可以使用LLDB命令调试App了。
通过debugserver启动App:
$ debugserver -x auto *:端口号 App可执行文件路径