一、什么叫動態調試
將程序運行起來,通過下斷點,打印等方式,查看參數、返回值、函數調用流程
二、Xcode的動態調試原理
- 關于GCC、LLVM、GDB、LLDB
~Xcode的編譯器發展歷程:GCC ---->LLVM
~Xcode的調試器發展歷程:GDB ---->LLDB - debugserver一開始存放在Mac的Xcode里面
~/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/12.1 (16B91)/DeveloperDiskImage.dmg/usr/bin/debugserver
- 當Xcode識別到手機設備是,Xcode會自動將debugserver安裝到iphone
~/Developer/usr/bin/debugserver
*Xcode調試的局限性
~一般情況下,只能調試通過Xcode安裝的APP三、動態調試任意APP
debugserver權限問題
*默認情況下,/Developer/usr/bin/debugserver缺少一定的權限,只能調試通過Xcode安裝的APP,無法調試其他APP
*如果希望調試其他APP,需要對debugserver重新簽名,簽上兩個關于調試相關的權限
~get-task-allow
~task_for_pid-allow
如何給debugserver簽名權限
*iphone上的/Developer目錄是制度的,無法對debugderver文件簽名,需要先把debugderver復制到Mac
*通過ldid命令導出文件以前的簽名權限
$ ldid -e debugserver > debugserver.entitlements
*geidebugderver.plist文件加上get-task-allow和task_for_pid-allow權限
- 通過ldid命令重新簽名
$ ldid -Sdebugserver.entitlements debugserver
- 將已經簽名好的權限的debugserver放到/usr/bin目錄,便于找發哦debugderver指令
//用于添加權限
$ chmod +x /usr/bin/debugserver
- 關于權限的簽名,可以使用codesign
# 查看權限信息
$ codesign -d --entitlements - debugserver
# 簽名權限
$ codesign -f -s - --entitlements debugserver.entitlements debugserver
#或者簡稱為
$ codesign -fs- --entitlements debugserver.entitlements debugserver
讓debugserver附加到某個APP進程
$ debugserver *:端口號 -a 進程
- :端口號
~使用iphone的某個端口啟動debugserver服務(只要不是保留端口號就行) - -a進程
~輸入APP的進程信息(進程ID或者進程名稱)
在Mac上啟動LLDB,遠程連接iphone上的debugserver服務
- 啟動LLDB
$ lldb
(lldb)
- 連接debugserver服務
(lldb) process connect connect://手機IP地址:debugserver服務端口號
- 使用LLDB的c命令讓程序先繼續運行
(lldb) c
- 接下來就可以使用LLDB命令調試APP
通過debugserver啟動APP
$ debugserver -x auto *:端口號 APP的可執行文件路徑
四、常用LLDB命令
- 指令的格式是
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-
value]] [argument [argument...]]
~ : 命令
~ : 子命令
~ : 命令操作
~ : 命令選項
~ : 命令參數
~ 比如給test函數設置斷點
breakpoint set -n test
- help
~ 查看指令的用法
~ 比如help breakpoint、help breakpoint set - experssion --
~ 執行一個表達式
expression self.view.backgroundColor = [UIColor redColor]
~ experssion、experssion--和指令print、p、call的效果一樣
~ experssion -O --和指令po的效果一樣
- thread backtrace
~打印線程的堆棧信息
~和指令bt的效果一樣 - thread return []
~ 讓函數返回某個值,不會智行斷點后面的代碼 - frame variable []
~打印當前棧幀的變量 - thread continue、continue、c :程序繼續運行
- thread step-over、next、n :單步運行,把子函數當做整體一步執行
- thread step-in、step、s :單步運行,遇到子函數會進入子函數
- thread step-out、finish :直接執行完當前函數的所有代碼
- thread step-inst-over、nexti、ni
- thread step-inst、stepi、si
- si、ni和s、n類似
~ s、n是源碼級別
~ si、ni是匯編指令級別 - breakpoint set
~設置斷點
~breakpoint set -a 函數地址
~breakpoint set -n 函數名
~breakpoint set -r 正則表達式
~breakpoint set -s 動態庫 -n 函數名
breakpoint set -n test
breakpoint set -n touchesBegan:withEvent:
breakpoint set -n "-[ViewController touchesBegan:withEvent:]"
breakpoint list:列出所有的斷點(每個斷點都有自己的編號)
breakpoint disable 斷點編號 :禁用斷點
breakpoint enable 斷點編號 :啟用斷點
breakpoint delete 斷點編號 :刪除斷點
breakpoint command add 斷點編號 :給斷點預先設置需要執行的命令,到處罰斷點時,就會按照順序執行,
breakpoint command list 斷點編號 : 查看某個斷點設置的命令
breakpoint command delete 斷點編號 :刪除某個斷點設置的命令
內存斷點 :在數據發生改變的時候觸發
watchpoint set variable 變量
watchpoint set variable self->age
watchpoint set expression 地址
watchpoint set expression &(self->_age)
watchpoint list
watchpoint disable 斷點編號
watchpoint enable 斷點編號
watchpoint delete 斷點編號
watchpoint command add 斷點編號
watchpoint command list 斷點編號
watchpoint command delete 斷點編號
image lookup
- image lookup -t 類型: 查找某個類型的信息
- image lookup -a 地址:根據內存地址查找再模塊中的位置
image lookup -n 符號或者函數名:查找某個符號或者函數的位置
image list 列出所加載的模塊信息
image list -o -f
打印出模塊的偏移地址,全路徑
小技巧
敲Enter,會自動執行上次的命令
絕對大部分指令都可以使用縮寫