一、概述
debugserver、lldb是协同工作的,debugserver依附在APP上,时刻监听APP的运行状态,并有控制APP执行的能力;lldb是在APP外部的,可以和debugserver建立连接,通过debugserver获取APP运行状态,并且能通知debugserver对APP做一些事情。在真机调试的时候,Xcode将debugserver加入到APP中,通过lldb来调试APP,那么同样也可以在命令行上对越狱手机上的任意APP进行调试。
Mac(Xcode(lldb)) -> APP(debugserver)
二、debugserver的获取与处理
Xcode
中debugserver
的位置:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/14.2
找到对应你的版本的,

然后双击dmg
挂载,可查看debugserver
位置:/usr/bin/debugserver

拷贝出来,进行签名
cp debugserver /Volumes/data/
通过Xcode
或直接创建一个en.plist
文件
<?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>
保存后对获取到的debugserver
进行重签名,赋予新权限
codesign -s - --entitlements en.plist -f debugserver
三、越狱手机安装debugserver
debugserver ip:port –a app
ip
允许连接的IP,一般是MAC的内网IP,port
对外开放的端口号(可以自定义)app
为要附加的应用名称。
zeno@zeno-macbook data % scp debugserver 172.16.4.75:/usr/bin/
iphone-xrdev:~ root# debugserver 172.16.4.70:12345 -a Penghuwan-mobile
debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1200.2.12
for arm64.
Attaching to process Penghuwan-mobile...
Listening to port 12345 for a connection from *...
四、MAC连接调试
在终端运行lldb
,连接debugserver
:
(lldb) process connect connect://172.16.4.75:12345
Process 4133 stopped
- thread #1, queue = ‘com.apple.main-thread’, stop reason = signal SIGSTOP
frame #0: 0x00000001d5f572d0 libsystem_kernel.dylibmach_msg_trap + 8 libsystem_kernel.dylib
mach_msg_trap:
-> 0x1d5f572d0 <+8>: ret
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x1d5f572d4 <+0>: mov x16, #-0x20
0x1d5f572d8 <+4>: svc #0x80
0x1d5f572dc <+8>: ret
Target 0: (token) stopped.
先输入c,让程序继续运行
(lldb) c
Process 4133 resuming
测试
(lldb) image list
[ 0] 0E5525EE-3FD9-34C9-AFE3-B4500F2A7CDE 0x0000000102714000 /private/var/containers/Bundle/Application/3057C19A-8055-4AFE-BDD6-076C450AC9CA/token.app/token (0x0000000102714000)
[ 1] A5F65EF3-BD32-370B-9821-B3E9CDA294D2 0x0000000103b5c000 /Users/zeno/Library/Developer/Xcode/iOS DeviceSupport/14.2 (18B92) arm64e/Symbols/usr/lib/dyld
[ 2] 5B1CDEC8-BEDC-31CD-9541-1974DA5B1AA8 0x0000000103c4c000 /usr/lib/substitute-inserter.dylib (0x0000000103c4c000)
[ 3] 540A1413-A396-391A-83DB-FE9EE2BC1413 0x00000001bd666000 /Users/zeno/Library/Developer/Xcode/iOS DeviceSupport/14.2 (18B92) arm64e/Symbols/usr/lib/libc++.1.dylib
五、lldb常用命令
LLDB指令
LLDB指令的格式是:
<command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]],其中,command代表命令,subcommand代表子命令,action代表命令的动作,- options 代表命令的选项,argument代表命令的参数,[]中的可以省略。
help命令,用于查看指令的用法,例如:help breakpoint、help breakpoint set
expression命令,执行一个表达式,例如:expression self.view.backgroundColor = [UIColor redColor],expression与print、p、call的效果一样
thread backtrace命令,打印线程的堆栈信息,与bt命令效果一样
thread return []命令,让函数直接返回某个值,不会执行断点后面的代码了,例如:thread return 3,返回了3
frame variable []命令,打印当前栈帧的变量
thread continue、continue、c命令,让程序继续运行
thread step-over、next、n命令,单步执行,把子函数当做一个整体,不会进入子函数
thread step-in、step、s命令,单步执行,遇到子函数会进入子函数内部
breakpoint set命令,设置断点,参数主要有以下几种:
breakpoint set -a 函数地址
breakpoint set -n 函数名
breakpoint set -r 正则表达式
breakpoint set -s 动态库 -n 函数名
breakpoint list命令,列出所有的断点,每个断点都有自己的编号
breakpoint delete 断点编号命令,删除某个断点
breakpoint command add 断点编号命令,给断点预先设置需要执行的命令,到触发断点时,就会按顺序执行
breakpoint command list 断点编号命令,查看某个断点的预设命令
watchpoint内存断点,就是当内存数据改变时,触发此断点,以便确认是谁修改了内存,子命令主要有以下几种:
watchpoint set variable 变量,例如:watchpoint set variable self->_age,当age变量改变时,断点就会触发,以便找到修改age内存的代码
watchpoint set expression 地址,例如:watchpoint set expression &self->_age
watchpoint list,列出所有的内存断点
watchpoint delete 断点编号,删除此内存断点
watchpoint command add 断点编号,给此内存断点,增加预设命令
image lookup,寻找模块信息,如果你想找某个类型、某个方法、某个地址在模块中的什么位置,就可以用这个命令,主要参数如下:
image lookup -t 类型,查找某个类型的信息,例如image lookup -t NSInterger
image lookup -a 地址,看看某个内存地址在模块中的位置
image lookup -n 符号或者函数名,查找某个符号或者函数的位置
image list,列出所加载的模块信息
一些小技巧:敲Enter会自动执行上次的命令、绝大部分命令可以使用缩写
breakpoint使用
1、给函数下断点
breakpoint set --name test1
breakpoint set -n test1
打印:
Breakpoint 2: where = LLDB`-[ViewController test1] + 23 at ViewController.m:25:5, address = 0x0000000109de9f97
断点位置信息,执行便能在该处断住。
连续下多个断点:
breakpoint set -n "-[ViewController save:]" -n "-[ViewController pause:]" -n "-[ViewController continues:]"
运行c
继续运行,n
单步执行,s
进入函数内部执行,finish执行到函数尾部。
2、查看断点列表
breakpoint list
打印
1: file = '/Users/hibo/Documents/test/LLDB/LLDB/ViewController.m', line = 21, exact_match = 0, locations = 1 Options: disabled
1.1: where = LLDB`-[ViewController touchesBegan:withEvent:] + 70 at ViewController.m:22:6, address = 0x0000000109de9f46, unresolved, hit count = 2 Options: disabled
2: name = 'test1', locations = 1, resolved = 1, hit count = 7
2.1: where = LLDB`-[ViewController test1] + 23 at ViewController.m:25:5, address = 0x0000000109de9f97, resolved, hit count = 7
3、禁用断点
breakpoint disable //禁用所有断点
breakpoint disable 1 //禁用第一个断点
4、启用断点
breakpoint enable //启用所有断点
breakpoint enable 1 //启用1处断点
5、删除所有断点
breakpoint delete
breakpoint delete 1
删除只能删除一组,不能单个删除
6、设置selector
breakpoint set --selector touchesBegan:withEvent:
将为所有该方法设置断点
7、设置文件中的selector
断点
breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
8、设置带有相同字符串的方法断点
breakpoint set -r Game:
打印:
Current breakpoints:
1: regex = 'Game:', locations = 3, resolved = 3, hit count = 0
1.1: where = LLDB`-[ViewController pauseGame:] + 43 at ViewController.m:31:5, address = 0x00000001010dff0b, resolved, hit count = 0
1.2: where = LLDB`-[ViewController continueGame:] + 43 at ViewController.m:34:5, address = 0x00000001010dff5b, resolved, hit count = 0
1.3: where = LinkPresentation`-[LPGameCenterInvitationMetadata setGame:], address = 0x00007fff2733e5e9, resolved, hit count = 0
如上也给其他带有Game
字符的类下了断点。
给某一个文件下的带有相同字符串的方法下断点:
breakpoint set --file ViewController.m -r Game
bt、frame命令
1、查看函数相关信息,使用p、down
追踪函数的调用和被调用关系
frame select
使用bt
命令查看函数调用堆栈
2、查找方法的调用者及方法名称
frame variable
methods、pviews
1、methods
打印当前对象的属性和方法
methods self
2、pviews
打印当前视图的层级结构
以上两个命令是lldb
插件名中的命令。chisel安装