一、前言
今天講述在蘋果日常開發中一個裝逼神器LLDB,是Xcode內置的動態調試工具. 在iOS系統程序開發中,會經常需要代碼調試的追蹤, 最常用的也是LLDB(low level debugger) .LLDB能更好的輔助開發者通過各種手段如修改變量進行測試,甚至能協助開發同學來定位bug.
LLDB是新一代高性能的調試器, 也是Mac OSX上Xcode的默認調試器, 支持在桌面和iOS設備模擬器上調試C,OC和C++以及Swift.
二、幫助
LLDB命令的格式如下:
<命令名稱> <命令動作> [-可選項 [可選項的值]] [參數1 [參數2...]]
LLDB命令是由各部分空格分割, 如果參數是包含空格, 則需要雙引號括起參數,如果參數本身中包含雙引號或反斜杠, 就需要使用反斜杠來進行轉義.
LLDB命令是非常多的, 完全記錄下來是不可能的, 而且還沒有必要. 可以利用help命令查看相關LLDB命令的用法.如下:
三、LLDB常見命令
3.1 breakpoint指令
示例Demo1
func test1(str: String) { self.test2(str: str) } func test2(str: String) { self.test3(str: str) } func test3(str: String) { print(str) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.test1(str: "zxy") }
通過breakpoint set -n 某函數名,來給某函數設置斷點
通過breakpoint list 打印出斷點列表
如果想一次性來設置多個斷點,也可以使用命令
breakpoint set -n 某函數名, -n 某函數名, -n 某函數名……
但是這樣設置就會將這幾個斷點設置為一組,與上面不一樣,一個個設置的.
breakpoint delete來刪除所有上次設置的斷點
breakpoint disable 斷點Id: 將設置過的斷點禁用,再次打印出breakpoint list 發現斷點式disable的
breakpoint set -r “字符串” 會遍歷整個工程,只要含該字符串的方法、函數都會下斷點
breakpoint set -f 類名 -l 斷點行數 會給該類名的具體行數加斷點
breakpoint set -file 類名 --selector 方法名 會給該類名的具體方法加斷點
breakpoint command add 標號 :斷點之后執行相應命令,以Done結束,類似於Edit breakpoint
總結如下:
3.2 流程控制
在Xcode調試Debugger時,經常有看到界面
對應的解釋和意義如下圖:
對應的命令如下
3.3 打印命令
p語句: 動態執行語句,可以查看基本數據的類型值, 如果用p命令查看的是對象的話, 只會返回對象的指針地址, p后面可以接變量、常量還可以接表達式
po語句: 打印對象的desc信息, 打印對象.
p和po的區別在於po會輸出對應的值, p會返回返回值的類型及命令結果的引用名
expression語句: 和p語句意思是一樣的
上面有&0,&1這樣的符號,是指對象的一個引用. 在控制台上可以用這個符號來操作對應的對象.
示例2
-(NSMutableArray<Person *> *)models{ if (!_models) { //arrayWithCapacity 節約內存。容量就是真實的內存中占用的大小。 _models = [NSMutableArray array]; } return _models; } - (void)viewDidLoad { [super viewDidLoad]; Person * p1 = [[Person alloc] init]; p1.name = @"one"; p1.age = 1; Person * p2 = [[Person alloc] init]; p2.name = @"two"; p2.age = 2; Person * p3 = [[Person alloc] init]; p3.name = @"three"; p3.age = 3; [self.models addObject:p1]; [self.models addObject:p2]; [self.models addObject:p3]; }
3.4 frame、bt、 up、 down
frame select 斷點排序值
frame variable :查看參數
bt:查看堆棧
再看示例1,點擊test1,test2,test3 。對test1設置斷點
可以通過up和down命令來查看步驟
up:向上查看
down:向下查看
3.5 thread、target
thread info: 輸出當前的線程
thread return :不再執行下面的代碼
target stop-hook add -o "frame variable": 斷點進入之后做的操作,這里是打印參數
3.6 image指令
image lookup -address 查找崩潰信息
image lookup -name 查看方法的來源
image lookup -type 查看成員,可以查看某個類class的所有成員變量以及屬性
總結圖如下:
四、ASLR
4.1 概述
ASLR(Address space layout randomization) 是一種針對緩沖區溢出的安全保護技術,通過對棧、堆、共享庫映射等線性區布局的隨機化,通過增加攻擊者預測目的預測目的地址的難度,防止攻擊者直接定位攻擊代碼位置,達到組織溢出攻擊的目的。
ASLR並不是蘋果Mac與iOS特有的,其他主流的操作系統也已經實現了ASLR。
4.2 講解
4.2.1 demo1代碼
- (void)viewDidLoad { [super viewDidLoad]; } - (void)eatWithObjc:(NSString *)objc { NSLog(@"吃到了%@",objc); } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self eatWithObjc:@"小蘑菇燉雞"]; } @end
運行App,然后利用Hopper disassembler v4查看eatWithObjc()函數的文件地址
然后打開MachOView查看可執行文件,pagezero為MachO首地址
通過image list 查看功能模塊的地址,第一個為MachO地址
然后我們講解一下內容,基本概念
4.2.2 demo2代碼
將斷點斷在a = 20,下面找一下全局變量放的位置。打印全局常量a在內存中的地址,以及MachO可執行文件的地址
將兩個地址相減,得到文件的偏移地址。0x0000000106ce8db0 - 0x0000000106ce5000 = 0x3DB0
然后打開MachOView查看
全局常量為10,找到MachOView的offset為0x3DB0,看Data LO為10,完美。
過掉斷點,發現a = 20了,再次查看內容,發現也已經為20
五、Cycript
Cycript 是由Cydia創始人Saurik推出的一款腳本語言,其混合了OC、JavaScript語法的解釋器,也就意味着可以在一個命令中使用OC或者JavaScript,甚至兩者並用,能夠掛鈎正在運行的進程,能夠在運行時修改很多東西。
提到解釋器,我們來普及兩個概念
高級語言分為兩個部分,解釋型語言和編譯型語言
解釋型語言:Python:直接將源代碼放進內存里面
編譯型語言:OC:將源代碼編譯成可執行文件,運行在設備上
總結
LLDB功能是非常強大的, 上面僅僅是介紹了一些簡單常用的命令, 還可以做進一步的探索. 下一篇我們將繼續講述LLDB的高級用法的操作, 使用LLDB操作指令可是開發裝逼的一種神器, 快使用起來吧. 希望本篇博客對大家理解使用LLDB有所幫助,如果覺得還不錯,給個點贊撒!!!