高效LLDB調試技巧

ps:本文爲之前學些是學習所記筆記,原文連接已經丟失,在此發表爲之後查閱方便,若有侵權請做者聯繫我,會立刻刪除。python

 

LLDB 命令仍是很多的,但有些都集成在 Xcode 的圖形化界面中,不必再去手動操做,這裏主要說一下使用起來更加高效的一些命令。shell

helpexpress

和大多數命令同樣,help 命令會顯示出全部的命令列表,對於相關的操做能夠直接查看。 若想查看某一條命令的話,直接在 help 後面加上對應的命令名稱。如:app

Objective-Ciphone

1ide

help print工具

p & call & po學習

先說 p  call, 兩者都是 expression — 的別名, p  print 的簡寫,同時能夠寫爲 pri,打印某個東西,能夠i是變量和表達式; call 爲調用某個方法,輸出變量也是能夠的。ui

po 通常用於打印對象,是 expression -O — 的別名。atom

 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>

  1. :命令選項,通常狀況下使用默認的便可,不須要特別標明。
  2. –: 命令選項結束符,表示全部的命令選項已經設置完畢,若是沒有命令選項,–能夠省略。
  3. : 要執行的表達式

 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

計算機生成了可選文字:
31 — ( 
) someMethod 
BOOL 
32 
33 
NSString 
*a 
34 
35 
36 
NSLog ; 
return YES;

  • 咱們只需在方法的開始位置加一個斷點,當程序中斷的時候,輸入命令便可:
    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

"

 

能夠看到,LLDBModel這個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 腳本使用。

相關文章
相關標籤/搜索