一、%log
的使用
%log
是 logo 的日志语法,可以 tweak 项目的方法内部,可以帮我们打印出许多信息
- 方法调用者的详细信息
- 方法名字
- 方法参数的详细信息
比如编写如下 hook 代码:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
%log;
%orig;
}
我们可以得到如下日志,非常详细:
-[<QQRecommendViewController: 0x1160c5c00> tableView:<UITableView: 0x1169cf600; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x2829c2250>; layer = <CALayer: 0x28276dca0>; contentOffset: {0, -16}; contentSize: {375, 602.5}; adjustedContentInset: {64, 0, 49, 0}> didSelectRowAtIndexPath:<NSIndexPath: 0xc000000000a00116> {length = 2, path = 1 - 5}]
从上面的日志,我们可以获得许多信息:
- 方法调用者的详细信息
QQRecommendViewController
- 方法名字
tableView: didSelectRowAtIndexPath:
- 方法参数的详细信息
UITableView
NSIndexPath
基于上面的效果,我们有一个大胆的想法,如果我们把一个 '控制器' 里面的所有方法像上面,调用的时候,把详细日志打印出来,那么是不是我们就非常方法追踪我们需要的信息了呢?
二、logify.pl 的使用
基于我们对 %log
的猜想,logify.pl 这个工具已经帮我们实现了该功能。
logify.pl 会把我们指定 .h 文件里面的所有方法,包装打印日志,并且用
%orig
维持原有功能,生成一个 tweak 文件。
执行 logify.pl QQChatViewController.h > QQChatViewController.x
指令,生成 tweak 文件,QQChatViewController.x
部分内容如下:
%hook QQChatViewController
- (void)setNewestFeedRequestID:(long long )newestFeedRequestID { %log; %orig; }
- (long long )newestFeedRequestID { %log; long long r = %orig; NSLog(@" = %lld", r); return r; }
%end
我们发送一条信息,就能得到如下调用链:

QQChatViewController.x 可能make
会遇到的编译错误,我们一般做如下操作:
- 删掉 _weak
- 删掉 inout
- 删掉或者声明协议
@protocol xxxDelegate;
- 删掉
-(void).css_destruct{%log;%orig;}
- 声明缺失的类信息
@class xxPerson, xxCar;
三、动态调试
- 关于 GCC、GDB、LLVM、LLDB
- Xcode 的编译器发展历程: GCC → LLVM
- Xcode 的调试器发展历程: GDB → LLDB
- debugserver
- debugserver 一开始存放在 Xcode 里面
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSuppor/9.1
- 当 Xcode 识别到手机设备时,Xcode 会自动将 debugserver 安装到 iPhone 上
/developer/usr/bin/debugserver
- Xcode 动态调试局限性:一般情况下,只能调试通过 Xcode 安装的 App
-
Xcode 调试 App 的原理
Xcode 调试 App 的原理
四、如何让 LLDB 和 debugserver 能调试所有 APP
- 找到手机上
/Developer/usr/bin
目录下的debugserver
可执行文件,导入 Mac 电脑中。 - 创建如下授权文件:
debugserver.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key> <true/>
<key>run-unsigned-code</key> <true/>
<key>get-task-allow</key> <true/>
<key>task_for_pid-allow</key> <true/>
</dict>
</plist>
- 执行
ldid -Sdebugserver.entitlements debugserver
指令,把权限重新签名给 debugserver。 - 将 debugserver 放入 iPhone 的
/usr/local/bin
目录下,并chmod +x debugserver
赋予可执行文件(为什么不覆盖原来 iPhone 上的呢?第一不影响原来 Xcode 的调用,第二该目录不能全局执行,第三该目录是只读目录) - 至此,iPhone 上的 debugserver 配置完毕,原本逻辑是要使用 Xcode 调用 LLDB 来操纵 debugserver 的,但是 Xcode 的弊端是只能调试 Xcode 自己运行的项目,所以我们现在要使用 Mac 终端来控制 LLDB。

- iPhone 终端执行
debugserver 192.168.0.187:10011 -a QQ
指令,命令行进入等待192.168.0.187
来链接的提示:
iPhone:/usr/local/bin root# debugserver 192.168.0.187:10011 -a QQ
debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-900.3.87
for arm64.
Attaching to process QQ...
Listening to port 10011 for a connection from 192.168.0.187...
- iPhone 终端执行
lldb
进入 lldb 模式:成功链接会如下显示
carrotdeMacBook-Pro:~ carrot__lsp$ lldb
(lldb) process connect connect://192.168.0.67:10011
Process 21025 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x000000019632f0f4 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
-> 0x19632f0f4 <+8>: ret
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x19632f0f8 <+0>: mov x16, #-0x20
0x19632f0fc <+4>: svc #0x80
0x19632f100 <+8>: ret
Target 0: (QQ) stopped.
(lldb)
此时,debug 的应用程序会进入断点模式,会卡住。出入 c
回车,即继续。
五、debugserver 和 LLDB 链接可能遇到的问题
- debugserver 一输入监听指令,就退出:
iPhone:~ root# debugserver *:10011 -a ting
debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-900.3.87
for arm64.
Attaching to process ting...
Listening to port 10011 for a connection from 127.0.01...
Failed to get connection from a remote gdb process.
Exiting.
解决方案:
-
debugserver *:10011 -a ting
不要填写*
号,直接用 Mac 地址代替。 - 授权有问题,请使用上面第四点给的授权文件给 debugserver 授权
- 可能 usbmux 模式有问题,直接用 WiFi 模式链接。
网友评论