ps:本文為以前學些是學習所記筆記,原文鏈接已經丟失,在此發表為以后查閱方便,如有侵權請作者聯系我,會馬上刪除。
LLDB 命令還是不少的,但有些都集成在 Xcode 的圖形化界面中,沒必要再去手動操作,這里主要說一下使用起來更加高效的一些命令。
help
和大多數命令一樣,help 命令會顯示出所有的命令列表,對於相關的操作可以直接查看。 若想查看某一條命令的話,直接在 help 后面加上對應的命令名稱。如:
Objective-C
| 1 |
help print |
p & call & po
先說 p 和 call, 二者都是 expression — 的別名, p 為 print 的簡寫,同時可以寫為 pri,打印某個東西,可以i是變量和表達式; call 為調用某個方法,輸出變量也是可以的。
po 一般用於打印對象,是 expression -O — 的別名。
p 和 po 的區別在於使用 po 只會輸出對應的值,而 p 則會返回值的類型以及命令結果的引用名。如:
Objective-C
| 1 2 3 4 5 6 7 8 |
(lldb) p self.model.number (float) $4 = 98 (lldb) p self.model.name (NSString *) $5 = nil (lldb) po self.model.number 98 (lldb) po self.model.words Hello |
expression
expression 命令的作用是執行一個表達式,並將表達式返回的結果輸出。expression的完整語法是這樣的:
Objective-C
| 1 |
expression <cmd-options> -- <expr> |
- :命令選項,一般情況下使用默認的即可,不需要特別標明。
- –: 命令選項結束符,表示所有的命令選項已經設置完畢,如果沒有命令選項,–可以省略。
- : 要執行的表達式
說 expression 是LLDB里面最重要的命令都不為過。因為他能實現2個功能。
- 執行某個表達式。 我們在代碼運行過程中,可以通過執行某個表達式來動態改變程序運行的軌跡。 假如我們在運行過程中,突然想把 self.view 顏色改成紅色,看看效果。我們不必寫下代碼,重新run,只需暫停程序,用expression改變顏色,再刷新一下界面,就能看到效果
- Objective-C
| 1 2 3 4 |
// 改變顏色 (lldb) expression -- self.view.backgroundColor = [UIColor redColor] // 刷新界面 (lldb) expression -- (void)[CATransaction flush] |
將返回值輸出。 也就是說我們可以通過expression來打印東西。 假如我們想打印 self.view:
- Objective-C
| 1 2 |
(lldb) expression -- self.view (UIView *) $1 = 0x00007fe322c18a10 |
thread
backtrace & bt
此命令一般用於將線程的堆棧打印出來,一般在程序出現 crash的時候調用。如;
Objective-C
| 1 2 3 4 5 6 7 8 9 |
(lldb) thread backtrace * thread #1: tid = 0xdd42, 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11 * frame #1: 0x000000010aa9f75e TLLDB`-[ViewController viewDidLoad](self=0x00007fa270e1f440, _cmd="viewDidLoad") + 174 at ViewController.m:23 frame #2: 0x000000010ba67f98 UIKit`-[UIViewController loadViewIfRequired] + 1198 frame #3: 0x000000010ba682e7 UIKit`-[UIViewController view] + 27 frame #4: 0x000000010b93eab0 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 61 frame #5: 0x000000010b93f199 UIKit`-[UIWindow _setHidden:forced:] + 282 frame #6: 0x000000010b950c2e UIKit`-[UIWindow makeKeyAndVisible] + 42 |
bt 為 thread backtrace 的別名,直接使用 bt 和使用上面那一長串是一個效果。
thread return
Debug的時候,也許會因為各種原因,我們不想讓代碼執行某個方法,或者要直接返回一個想要的值。這時候就該thread return上場了。
- Objective-C
| 1 |
thread return [<expr>] |
thread return可以接受一個表達式,調用命令之后直接從當前的堆棧中返回表達式的值。
e.g: 我們有一個 someMethod 方法,默認情況下是返回YES。我們想要讓他返回NO

- 我們只需在方法的開始位置加一個斷點,當程序中斷的時候,輸入命令即可:
Objective-C
| 1 |
(lldb) thread return NO |
效果相當於在斷點位置直接調用 *return NO; *,不會執行斷點后面的代碼.
target
對於target這個命令,我們用得最多的可能就是 target modules lookup。由於 LLDB 給 target modules 取了個別名 *image *,所以這個命令我們又可以寫成 *image lookup *。
image lookup –address
當我們有一個地址,想查找這個地址具體對應的文件位置,可以使用 image lookup –address ,簡寫為 image lookup -a。 e.g: 當我們發生一個crash
Objective-C
| 1 2 3 4 5 6 7 8 9 |
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 1 beyond bounds for empty NSArray' *** First throw call stack: ( 0 CoreFoundation 0x000000010accde65 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010a746deb objc_exception_throw + 48 2 CoreFoundation 0x000000010ac7c395 -[__NSArray0 objectAtIndex:] + 101 3 TLLDB 0x000000010a1c3e36 -[ViewController viewDidLoad] + 86 4 UIKit 0x000000010b210f98 -[UIViewController loadViewIfRequired] + 1198 5 UIKit 0x000000010b2112e7 -[UIViewController view] + 27 |
我們可以看到是由於-[__NSArray0 objectAtIndex:]:超出邊界而導致的crash,但是objectAtIndex:的代碼到底在哪兒呢?
Objective-C
| 1 2 3 |
(lldb) image lookup -a 0x000000010a1c3e36 Address: TLLDB[0x0000000100000e36] (TLLDB.__TEXT.__text + 246) Summary: TLLDB`-[ViewController viewDidLoad] + 86 at ViewController.m:32 |
根據0x000000010a1c3e36 -[ViewController viewDidLoad]里面的地址,使用image lookup –address查找,我們可以看到代碼位置在ViewController.m里面的32行。
image lookup –name
當我們想查找一個方法或者符號的信息,比如所在文件位置等。我們可以使用 image lookup –name ,簡寫為 *image lookup -n *。
e.g: 剛剛遇到的真問題,某個第三方SDK用了一個我們項目里原有的第三方庫,庫里面對 NSDictionary 添加了 category 。也就是有2個 class 對 NSDictionary 添加了名字相同的 category,項目中調用自己的 category 的地方實際走到了第三方SDK里面去了。最大的問題是,這2個同名 category 方法行為並不一致,導致出現 bug
現在問題來了,怎么尋找到底是哪個第三方SDK?方法完全包在.a里面。
其實只需使用image lookup -n即可:
Objective-C
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
(lldb) image lookup -n dictionaryWithXMLString: 2 matches found in /Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo: Address: BaiduIphoneVideo[0x00533a7c] (BaiduIphoneVideo.__TEXT.__text + 5414908) Summary: BaiduIphoneVideo`+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:] at XmlDictionary.m Module: file = "/Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo", arch = "armv7" CompileUnit: id = {0x00000000}, file = "/Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m", language = "Objective-C" Function: id = {0x23500000756}, name = "+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:]", range = [0x005a6a7c-0x005a6b02) FuncType: id = {0x23500000756}, decl = XmlDictionary.m:189, clang_type = "NSDictionary *(NSString *)" Blocks: id = {0x23500000756}, range = [0x005a6a7c-0x005a6b02) LineEntry: [0x005a6a7c-0x005a6a98): /Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m Symbol: id = {0x0000f2d5}, range = [0x005a6a7c-0x005a6b04), name="+[NSDictionary(SAPIXmlDictionary) dictionaryWithXMLString:]" Variable: id = {0x23500000771}, name = "self", type = "Class", location = [sp+32], decl = Variable: id = {0x2350000077e}, name = "_cmd", type = "SEL", location = [sp+28], decl = Variable: id = {0x2350000078b}, name = "string", type = "NSString *", location = [sp+24], decl = XmlDictionary.m:189 Variable: id = {0x23500000799}, name = "data", type = "NSData *", location = [sp+20], decl = XmlDictionary.m:192 Address: BaiduIphoneVideo[0x012ee160] (BaiduIphoneVideo.__TEXT.__text + 19810016) Summary: BaiduIphoneVideo`+[NSDictionary(XMLDictionary) dictionaryWithXMLString:] at XMLDictionary.m Module: file = "/Users/jiangliancheng/Library/Developer/Xcode/DerivedData/VideoIphone-aivsnqmlwjhxapdlvmdmrubbdxpq/Build/Products/Debug-iphoneos/BaiduIphoneVideo.app/BaiduIphoneVideo", arch = "armv7" CompileUnit: id = {0x00000000}, file = "/Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m", language = "Objective-C" Function: id = {0x79900000b02}, name = "+[NSDictionary(XMLDictionary) dictionaryWithXMLString:]", range = [0x01361160-0x0136119a) FuncType: id = {0x79900000b02}, decl = XMLDictionary.m:325, clang_type = "NSDictionary *(NSString *)" Blocks: id = {0x79900000b02}, range = [0x01361160-0x0136119a) LineEntry: [0x01361160-0x01361164): /Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m Symbol: id = {0x0003a1e9}, range = [0x01361160-0x0136119c), name="+[NSDictionary(XMLDictionary) dictionaryWithXMLString:]" Variable: id = {0x79900000b1e}, name = "self", type = "Class", location = r0, decl = Variable: id = {0x79900000b2c}, name = "_cmd", type = "SEL", location = r1, decl = Variable: id = {0x79900000b3a}, name = "string", type = "NSString *", location = r2, decl = XMLDictionary.m:325 Variable: id = {0x79900000b4a}, name = "data", type = "NSData *", location = r2, decl = XMLDictionary.m:327 |
東西有點多,我們只需關注里面的file這一行:
Objective-C
| 1 2 |
CompileUnit: id = {0x00000000}, file = "/Users/jiangliancheng/Development/Work/iOS_ShareLib/SharedLib/Srvcs/BDPassport4iOS/BDPassport4iOS/SAPI/Extensive/ThirdParty/XMLDictionary/XmlDictionary.m", language = "Objective-C" CompileUnit: id = {0x00000000}, file = "/Users/wingle/Workspace/qqlive4iphone/iphone_4.0_fabu_20150601/Common_Proj/mobileTAD/VIDEO/Library/Third Party/XMLDictionary/XMLDictionary.m", language = "Objective-C" |
可以清晰的看到,LLDB給我們找出來了這個方法的位置。 當然這個命令也可以找到方法的其他相關信息,比如參數等.
image lookup –type
當我們想查看一個類型的時候,可以使用 image lookup –type,簡寫為image lookup -t:
e.g: 我們來看看Model的類型:
Objective-C
| 1 2 3 4 5 6 7 8 9 10 |
(lldb) image lookup -t Model Best match found in /Users/jiangliancheng/Library/Developer/Xcode/DerivedData/TLLDB-beqoowskwzbttrejseahdoaivpgq/Build/Products/Debug-iphonesimulator/TLLDB.app/TLLDB: id = {0x30000002f}, name = "Model", byte-size = 32, decl = Modek.h:11, clang_type = "@interface Model : NSObject{ NSString * _bb; NSString * _cc; NSString * _name; } @property ( getter = name,setter = setName:,readwrite,nonatomic ) NSString * name; @end " |
可以看到,LLDB把Model這個class的所有屬性和成員變量都打印了出來,當我們想了解某個類的時候,直接使用 image lookup -t 即可。
其他
可以直接使用LLDB打開模擬器位置:
Objective-C
| 1 2 3 |
(lldb) po NSHomeDirectory() /Users/mfw/Library/Developer/CoreSimulator/Devices/EAFE74A5-4C53-42CE-8B40-141380D73A6D/data/Containers/Data/Application/B4C48D8B-BD8B-4246-B9D7-15FEC3CA8662 (lldb) platform shell open /Users/mfw/Library/Developer/CoreSimulator/Devices/EAFE74A5-4C53-42CE-8B40-141380D73A6D/data/Containers/Data/Application/B4C48D8B-BD8B-4246-B9D7-15FEC3CA8662 |
常用的Debug快捷鍵
debug的時候,使用快捷鍵是一個很好的習慣,我簡單列舉了幾個debug的快捷鍵
| 功能 |
命令 |
| 暫停/繼續 |
cmd + ctrl + Y |
| 斷點失效/生效 |
cmd + Y |
| 控制台顯示/隱藏 |
cmd + shift + Y |
| 光標切換到控制台 |
cmd + shift + C |
| 清空控制台 |
cmd + K |
| step over |
F6 |
| step into |
F7 |
| step out |
F8 |
| 工程導航器 |
Command+1 |
| 顯示/隱藏導航器面板 |
Command+0 |
| 顯示/隱藏實用工具面板 |
Command+Option+0 |
| 打開Assistant Editor |
項目導航器中選中文件執行Option+左鍵點擊操作 |
| 展示方法列表 |
Control+6(鍵入方法/變量名+Enter跳轉 |
| 快速打開 |
Command + Shift + O |
| 文檔和參考 |
Command + Shift + 0 |
| 快速幫助 |
在類或者方法名上執行Option + Left-click操作 |
| 展示當前你在工程導航器中打開的文件 |
Command + Shift + J |
| 迷你窗口,可任意選擇位置 |
Command + Option + Shift + Left-click |
End
這是我比較常用的一些命令,不全但是有效,像那些 breakpoint 的功能,若不是使用 lldb調試可執行文件的話,直接使用 Xcode 的功能效果會更加顯著一些。若想使用一些高級命令,可結合 python 腳本使用。
