LLDB

隨著Xcode 5的發(fā)布,LLDB調(diào)試器已經(jīng)取代了GDB宿亡,成為了Xcode工程中默認的調(diào)試器常遂。它與LLVM編譯器一起,帶給我們更豐富的流程控制和數(shù)據(jù)檢測的調(diào)試功 能挽荠。LLDB為Xcode提供了底層調(diào)試環(huán)境克胳,其中包括內(nèi)嵌在Xcode IDE中的位于調(diào)試區(qū)域的控制面板,在這里我們可以直接調(diào)用LLDB命令圈匆。如圖1所示:

圖1:位于Xcode調(diào)試區(qū)域的控制臺

在本文中漠另,我們主要整理一下LLDB調(diào)試器提供給我們的調(diào)試命令,更詳細的內(nèi)容可以查看The LLDB Debugger跃赚。

LLDB命令結(jié)構(gòu)

在使用LLDB前笆搓,我們需要了解一下LLDB的命令結(jié)構(gòu)及語法,這樣可以盡可能地挖掘LLDB的潛能纬傲,以幫助我們更充分地利用它满败。

LLDB命令的語法有其通用結(jié)構(gòu),通常是以下形式的:

1

?[?[...]]??[-options?[option-value]]?[argument?[argument...]]

其中:

(命令)和(子命令):LLDB調(diào)試命令的名稱叹括。命令和子命令按層級結(jié)構(gòu)來排列:一個命令對象為跟隨其的子命令對象創(chuàng)建一個上下文算墨,子命令又為其子命令創(chuàng)建一個上下文,依此類推汁雷。

:我們想在前面的命令序列的上下文中執(zhí)行的一些操作净嘀。

:行為修改器(action modifiers)报咳。通常帶有一些值。

:根據(jù)使用的命令的上下文來表示各種不同的東西面粮。

LLBD命令行的解析操作在執(zhí)行命令之前完成少孝。上面的這些元素之間通過空格來分割,如果某一元素自身含有空格熬苍,則可以使用雙引用稍走。而如果元素中又包含雙引號,則可以使用反斜杠柴底;或者元素使用單引號婿脸。如下所示:

1

2(lldb)?command?[subcommand]?-option"some?\"quoted\"?string"

(lldb)?command?[subcommand]?-option'some?"quoted"?string'

這種命令解析設(shè)計規(guī)范了LLDB命令語法,并對所有命令做了個統(tǒng)一柄驻。

命令選項

LLDB中的命令選項有規(guī)范形式和縮寫形式兩種格式狐树。以設(shè)置斷點的命令breakpoint set為例,以下列表了其部分選項的格式鸿脓,其中括號中的是規(guī)范形式:

1

2

3

4

5

6

7

8breakpoint?set

-M??(?--method??)

-S??(?--selector??)

-b??(?--basename??)

-f??(?--file??)

-l??(?--line??)

-n??(?--name??)

各選項的順序是任意的抑钟。如果后面的參數(shù)是以”–“開頭的,則在選項后面添加”—“作為選項的終止信號野哭,以告訴LLDB我們處理的選項的正確位置在塔。如下命令所示:

1

(lldb)?process?launch?--stop-at-entry?--?-program_arg_1?value?-program_arg_2?value

如上所示,命令的選項是—stop-at-entry拨黔,參數(shù)是-program_arg_1和-program_arg_2蛔溃,我們使用”—“將選項與參數(shù)作一下區(qū)分。

原始命令

LLDB命令解析器支持”原始(raw)“命令篱蝇,即沒有命令選項贺待,命令字符串的剩余部分未經(jīng)解析就傳遞給命令。例如零截,expression就是一個原始命令麸塞。

不過原始命令也可以有選項,如果命令字符串中有虛線涧衙,則在命令名與命令字符串之間放置一個選項結(jié)束符(—)來表明沒有命令標記喘垂。

我們可以通過help命令的輸出來查看一個命令是否是原始命令。

命令補全(Command Completion)

LLDB 支持源文件名绍撞,符號名,文件名得院,等等的命令補全(Commmand Completion)傻铣。終端窗口中的補全是通過在命令行中輸入一個制表符來初始化的。Xcode控制臺中的補全與在源碼編輯器中的補全方式是一樣的:補 全會在第三個字符被鍵入時自動彈出祥绞,或者通過Esc鍵手動彈出非洲。

一個命令中的私有選項可以有不同的完成者(completers)鸭限。如 breakpoint中的—file 選項作為源文件的完成者,—shlib 選項作為當前加載的庫的完成者两踏,等等败京。這些行為是特定的,例如梦染,如果指定—shlib 赡麦,且以—file 結(jié)尾,則LLDB只會列出由—shlib 指定的共享類庫帕识。

Python腳本

對于高級用戶來說泛粹,LLDB有一個內(nèi)置的Python 解析器,可以通過腳本命令來訪問肮疗。調(diào)試器中的所有特性在Python解析器中都可以作為類來訪問晶姊。這樣,我們就可以使用LLDB-Python庫來寫 Python函數(shù)伪货,并通過腳本將其加載到運行會話中们衙,以執(zhí)行一些更復雜的調(diào)試操作。

在命令行中調(diào)試程序

通常我們都是在Xcode中直接使用LLDB調(diào)試器碱呼,Xcode會幫我們完成很多操作蒙挑。當然,如果我們想讓自己看著更Bigger巍举,或者想了解下調(diào)試器具體的一些流程脆荷,就可以試試直接在終端使用LLDB命令來調(diào)試程序。在終端中使用LLDB調(diào)試器懊悯,我們需要了解以下內(nèi)容:

1.加載程序以備調(diào)試

2.將一個運行的程序綁定到LLDB

3.設(shè)置斷點和觀察點

4.控制程序的執(zhí)行

5.在調(diào)試的程序中導航

6.檢查狀態(tài)和值的變量

7.執(zhí)行替代代碼

了解在終端中這些操作是如何進行的蜓谋,可以幫助我們更深入的了解調(diào)試器在Xcode中是如何運作的。下面我們分步來介紹一下炭分。

指定需要調(diào)試的程序

首先我們需要設(shè)置需要調(diào)試的程序桃焕。我們可以使用如下命令做到這一點:

1

2$?lldb?/Projects/Sketch/build/Debug/Sketch.app

Current?executable?set?to'/Projects/Sketch/build/Debug/Sketch.app'(x86_64).

或者在運行l(wèi)ldb后,使用file命令來處理捧毛,如下所示:

1

2

3$?lldb

(lldb)?file?/Projects/Sketch/build/Debug/Sketch.app

Current?executable?set?to'/Projects/Sketch/build/Debug/Sketch.app'(x86_64).

設(shè)置斷點

在設(shè)置完程序后观堂,我們可能想設(shè)置一點斷點來調(diào)試程序。此時我們可以使用breakpoint set命令來設(shè)置斷點呀忧,這個命令簡單师痕、直觀,且有智能補全而账,接下來我們看看它的具體操作胰坟。

如果想在某個文件中的某行設(shè)置一個斷點,可使用以下命令:

1

(lldb)?breakpoint?set?--file?foo.c?--line?12

如果想給某個函數(shù)設(shè)置斷點泞辐,可使用以下命令:

1

(lldb)?breakpoint?set?--name?foo

如果想給C++中所有命名為foo的方法設(shè)置斷點笔横,可以使用以下命令:

1

(lldb)?breakpoint?set?--method?foo

如果想給Objective-C中所有命名為alignLeftEdges:的選擇器設(shè)置斷點竞滓,則可以使用以下命令:

1

(lldb)?breakpoint?set?--selector?alignLeftEdges:

我們可以使用—shlib 來將斷點限定在一個特定的可執(zhí)行庫中:

1

(lldb)?breakpoint?set?--shlib?foo.dylib?--name?foo

看吧,斷點設(shè)置命令還是很強大的吹缔。

如果我們想查看程序中所有的斷點商佑,則可以使用breakpoint list命令,如下所示:

1

2

3

4(lldb)?breakpoint?list

Current?breakpoints:

1:?name?='alignLeftEdges:',?locations?=?1,?resolved?=?1

1.1:?where?=?Sketch`-[SKTGraphicView?alignLeftEdges:]?+?33?at?/Projects/Sketch/SKTGraphicView.m:1405,?address?=?0x0000000100010d5b,?resolved,?hit?count?=?0

從上面的輸出結(jié)果可以看出厢塘,一個斷點一般有兩部分:

1.斷點的邏輯規(guī)范茶没,這一部分是用戶提供給breakpoint set命令的。

2.與規(guī)范匹配的斷點的位置俗冻。

如上所示礁叔,通過”breakpoint set —selector alignLeftEdges:“設(shè)置的斷點,其信息中會顯示出所有alignLeftEdges:方法的位置迄薄。

breakpoint list命令輸出列表顯示每個邏輯斷點都有一個整數(shù)標識琅关,如上所示斷點標識為1。而每個位置也會有一個標識讥蔽,如上所示的1.1涣易。

輸出列表中另一個信息是斷點位置是否是已解析的(resolved)。這個標識表示當與之相關(guān)的文件地址被加載到程序進行調(diào)試時冶伞,其位置是已解析的新症。例如,如果在共享庫中設(shè)置的斷點之后被卸載了响禽,則斷點的位置還會保留徒爹,但其不能再被解析。

不管是邏輯斷點產(chǎn)生的所有位置芋类,還是邏輯斷點解析的任何特定位置隆嗅,我們都可以使用斷點觸發(fā)命令來對其進行刪除、禁用侯繁、設(shè)置條件或忽略計數(shù)操作胖喳。例如,如果我們想添加一個命令贮竟,以在LLDB命中斷點1.1時打印跟蹤棧丽焊,則可以執(zhí)行以下命令

1

2

3

4(lldb)?breakpoint?command?add?1.1

Enter?your?debugger?command(s).?Type'DONE'to?end.

>?bt

>?DONE

如果想更詳細地了解”breakpoint command add”命令的使用,可以使用help幫助系統(tǒng)來查看咕别。

設(shè)置觀察點

作為斷點的補充技健,LLDB支持觀察點以在不中斷程序運行的情況下監(jiān)測一些變量。例如惰拱,我們可以使用以下命令來監(jiān)測名為global的變量的寫操作雌贱,并在(global==5)為真時停止監(jiān)測:

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

29

30

31

32

33

34

35

36

37

38

39

40(lldb)?watch?setvarglobal

Watchpoint?created:?Watchpoint?1:?addr?=?0x100001018?size?=?4?state?=?enabled?type?=?w

declare?@'/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'

(lldb)?watch?modify?-c'(global==5)'

(lldb)?watch?list

Current?watchpoints:

Watchpoint?1:?addr?=?0x100001018?size?=?4?state?=?enabled?type?=?w

declare?@'/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'

condition?='(global==5)'

(lldb)?c

Process?15562?resuming

(lldb)?about?to?write?to'global'...

Process?15562?stopped?and?was?programmatically?restarted.

Process?15562?stopped?and?was?programmatically?restarted.

Process?15562?stopped?and?was?programmatically?restarted.

Process?15562?stopped?and?was?programmatically?restarted.

Process?15562?stopped

*?thread#1:?tid?=?0x1c03,?0x0000000100000ef5?a.out`modify?+?21?at?main.cpp:16,?stop?reason?=?watchpoint?1

frame#0:?0x0000000100000ef5?a.out`modify?+?21?at?main.cpp:16

13

14??????static?void?modify(int32_t?&var)?{

15??????????++var;

->?16??????}

17

18??????int?main(int?argc,?char**?argv)?{

19??????????int?local?=?0;

(lldb)?bt

*?thread#1:?tid?=?0x1c03,?0x0000000100000ef5?a.out`modify?+?21?at?main.cpp:16,?stop?reason?=?watchpoint?1

frame#0:?0x0000000100000ef5?a.out`modify?+?21?at?main.cpp:16

frame#1:?0x0000000100000eac?a.out`main?+?108?at?main.cpp:25

frame#2:?0x00007fff8ac9c7e1?libdyld.dylib`start?+?1

(lldb)?framevarglobal

(int32_t)?global?=?5

(lldb)?watch?list?-v

Current?watchpoints:

Watchpoint?1:?addr?=?0x100001018?size?=?4?state?=?enabled?type?=?w

declare?@'/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'

condition?='(global==5)'

hw_index?=?0??hit_count?=?5?????ignore_count?=?0

(lldb)

可以使用help watchpoint來查看該命令的使用。

使用LLDB來啟動程序

一旦指定了調(diào)試哪個程序,并為其設(shè)置了一些斷點后帽芽,就可以開始運行程序了。我們可以使用以下命令來啟動程序:

1

2

3(lldb)?process?launch

(lldb)?run

(lldb)?r

我 們同樣可以使用進程ID或進程名來連接一個已經(jīng)運行的程序翔冀。當使用名稱來連接一個程序時导街,LLDB支持—waitfor選項。這個選項告訴LLDB等待下 一個名稱為指定名稱的程序出現(xiàn)纤子,然后連接它搬瑰。例如,下面3個命令都是用于連接Sketch程序(假定其進程ID為123):

1

2

3(lldb)?process?attach?--pid?123

(lldb)?process?attach?--name?Sketch

(lldb)?process?attach?--name?Sketch?--waitfor

啟動或連接程序后控硼,進程可能由于某些原因而停止泽论,如:

1

2

3

4

5

6(lldb)?process?attach?-p?12345

Process?46915?Attaching

Process?46915?Stopped

1?of?3?threads?stoppedwithreasons:

*?thread#1:?tid?=?0x2c03,?0x00007fff85cac76a,?where?=?libSystem.B.dylib`__getdirentries64?+?10,

stop?reason?=?signal?=?SIGSTOP,?queue?=?com.apple.main-thread

注意“1 of 3 threads stopped with reasons:”及其下面一行。在多線程環(huán)境下卡乾,在內(nèi)核實際返回控制權(quán)給調(diào)試器前翼悴,可能會有多個線程命中同一個斷點。在這種情況下幔妨,我們可以在停止信息中看到所有因此而停止的線程鹦赎。

控制程序

啟動程序后,LLDB允許程序在到達斷點前繼續(xù)運行误堡。LLDB中流程控制的命令都在thread命令層級中古话。如下所示:

1

2

3(lldb)?threadcontinue

Resuming?thread?0x2c03inprocess?46915

Resuming?process?46915

另外,還有以下命令:

1

2

3

4

5(lldb)?thread?step-in//?The?same?as?"step"?or?"s"?in?GDB.

(lldb)?thread?step-over//?The?same?as?"next"?or?"n"?in?GDB.

(lldb)?thread?step-out//?The?same?as?"finish"?or?"f"?in?GDB.

(lldb)?thread?step-inst//?The?same?as?"stepi"?/?"si"?in?GDB.

(lldb)?thread?step-over-inst//?The?same?as?"nexti"?/?"ni"?in?GDB.

LLDB還提供了run until line按步調(diào)度模式锁施,如:

1

lldb)?thread?until?100

這條命令會運行線程陪踩,直到當前frame到達100行。如果代碼在運行的過程中跳過了100行悉抵,則當frame被彈出棧后終止執(zhí)行肩狂。

查看線程狀態(tài)

在進程停止后,LLDB會選擇一個當前線程和線程中當前幀(frame)基跑。很多檢測狀態(tài)的命令可以用于這個線程或幀婚温。

為了檢測進程的當前狀態(tài),可以從以下命令開始:

1

2

3

4

5(lldb)?thread?list

Process?46915?state?is?Stopped

*?thread#1:?tid?=?0x2c03,?0x00007fff85cac76a,?where?=?libSystem.B.dylib`__getdirentries64?+?10,?stop?reason?=?signal?=?SIGSTOP,?queue?=?com.apple.main-thread

thread#2:?tid?=?0x2e03,?0x00007fff85cbb08a,?where?=?libSystem.B.dylib`kevent?+?10,?queue?=?com.apple.libdispatch-manager

thread#3:?tid?=?0x2f03,?0x00007fff85cbbeaa,?where?=?libSystem.B.dylib`__workq_kernreturn?+?10

星號(*)表示thread #1為當前線程媳否。為了獲取線程的跟蹤棧栅螟,可以使用以下命令:

1

2

3

4

5

6

7

8

9

10

11

12

13(lldb)?thread?backtrace

thread#1:?tid?=?0x2c03,?stop?reason?=?breakpoint?1.1,?queue?=?com.apple.main-thread

frame#0:?0x0000000100010d5b,?where?=?Sketch`-[SKTGraphicView?alignLeftEdges:]?+?33?at?/Projects/Sketch/SKTGraphicView.m:1405

frame#1:?0x00007fff8602d152,?where?=?AppKit`-[NSApplication?sendAction:to:from:]?+?95

frame#2:?0x00007fff860516be,?where?=?AppKit`-[NSMenuItem?_corePerformAction]?+?365

frame#3:?0x00007fff86051428,?where?=?AppKit`-[NSCarbonMenuImpl?performActionWithHighlightingForItemAtIndex:]?+?121

frame#4:?0x00007fff860370c1,?where?=?AppKit`-[NSMenu?performKeyEquivalent:]?+?272

frame#5:?0x00007fff86035e69,?where?=?AppKit`-[NSApplication?_handleKeyEquivalent:]?+?559

frame#6:?0x00007fff85f06aa1,?where?=?AppKit`-[NSApplication?sendEvent:]?+?3630

frame#7:?0x00007fff85e9d922,?where?=?AppKit`-[NSApplication?run]?+?474

frame#8:?0x00007fff85e965f8,?where?=?AppKit`NSApplicationMain?+?364

frame#9:?0x0000000100015ae3,?where?=?Sketch`main?+?33?at?/Projects/Sketch/SKTMain.m:11

frame#10:?0x0000000100000f20,?where?=?Sketch`start?+?52

如果想查看所有線程的調(diào)用棧,則可以使用以下命令:

1

(lldb)?thread?backtrace?all

查看調(diào)用棧狀態(tài)

檢查幀參數(shù)和本地變量的最簡便的方式是使用frame variable命令:

1

2

3

4

5

6

7(lldb)?frame?variable

self?=?(SKTGraphicView?*)?0x0000000100208b40

_cmd?=?(struct?objc_selector?*)?0x000000010001bae1

sender?=?(id)?0x00000001001264e0

selection?=?(NSArray?*)?0x00000001001264e0

i?=?(NSUInteger)?0x00000001001264e0

c?=?(NSUInteger)?0x00000001001253b0

如果沒有指定任何變量名篱竭,則會顯示所有參數(shù)和本地變量力图。如果指定參數(shù)名或變量名,則只打印指定的值掺逼。如:

1

2(lldb)?frame?variable?self

(SKTGraphicView?*)?self?=?0x0000000100208b40

frame variable命令不是一個完全的表達式解析器吃媒,但它支持一些簡單的操作符,如&,*,–>,[]。這個數(shù)組括號可用于指針赘那,以將指針作為數(shù)組處理刑桑。如下所示:

1

2

3

4

5

6

7

8

9(lldb)?frame?variable?*self

(SKTGraphicView?*)?self?=?0x0000000100208b40

(NSView)?NSView?=?{

(NSResponder)?NSResponder?=?{

...

(lldb)?frame?variable?&self

(SKTGraphicView?**)?&self?=?0x0000000100304ab

(lldb)?frame?variable?argv[0]

(char?const?*)?argv[0]?=?0x00007fff5fbffaf8"/Projects/Sketch/build/Debug/Sketch.app/Contents/MacOS/Sketch"

frame variable命令會在變量上執(zhí)行”對象打印”操作。目前募舟,LLDB只支持Objective-C打印祠斧,使用的是對象的description方法。

如果想查看另外一幀拱礁,可以使用frame select命令琢锋,如下所示:

1

2(lldb)?frame?select?9

frame#9:?0x0000000100015ae3,?where?=?Sketch`function1?+?33?at?/Projects/Sketch/SKTFunctions.m:11

小結(jié)

以上所介紹的命令可以讓我們在終端中直接調(diào)試程序。當然呢灶,很多命令也可以在Xcode中直接使用吴超。這些命令可以讓我們了解程序運行的狀態(tài),當然有些狀態(tài)可以在Xcode中了解到鸯乃。建議在調(diào)試過程中鲸阻,可以多使用這些命令。

如果想了解這一過程中使用的各種命令飒责,可以查看蘋果的官方文檔赘娄。

在Xcode中調(diào)試程序

對于我們?nèi)粘5拈_發(fā)工作來說,更多的時候是在Xcode中進行調(diào)試工作宏蛉。因此上面所描述的流程遣臼,其實Xcode已經(jīng)幫我們完成了大部分的工作,而且很多東西也可以在Xcode里面看到拾并。因此揍堰,我們可以把精力都集中在代碼層面上。

蘋果的官方文檔中列出了我們在調(diào)試中能用到的一些命令嗅义,我們在這重點講一些常用的命令屏歹。

打印

打印變量的值可以使用print命令,該命令如果打印的是簡單類型之碗,則會列出簡單類型的類型和值蝙眶。如果是對象,還會打印出對象指針地址褪那,如下所示:

1

2

3

4

5

6

7

8(lldb)?print?a

(NSInteger)?$0?=?0

(lldb)?print?b

(NSInteger)?$1?=?0

(lldb)?print?str

(NSString?*)?$2?=?0x0000000100001048?@"abc"

(lldb)?print?url

(NSURL?*)?$3?=?0x0000000100206cc0?@"abc"

在輸出結(jié)果中我們還能看到類似于$0,$1這樣的符號幽纷,我們可以將其看作是指向?qū)ο蟮囊粋€引用,我們在控制面板中可以直接使用這個符號來操作對應的對象博敬,這些東西存在于LLDB的全名空間中友浸,目的是為了輔助調(diào)試。如下所示:

1

2

3

4(lldb)?exp $0?=?100

(NSInteger)?$9?=?100

(lldb)?p?a

(NSInteger)?$10?=?100

另外$后面的數(shù)值是遞增的偏窝,每打印一個與對象相關(guān)的命令收恢,這個值都會加1武学。

上面的print命令會打印出對象的很多信息,如果我們只想查看對象的值的信息伦意,則可以使用po(print object的縮寫)命令火窒,如下所示:

1

2(lldb)?po?str

abc

當然,po命令是”exp -O —“命令的別名驮肉,使用”exp -O —”能達到同樣的效果沛鸵。

對于簡單類型,我們還可以為其指定不同的打印格式缆八,其命令格式是print/,如下所示:

1

2(lldb)?p/x?a

(NSInteger)?$13?=?0x0000000000000064

格式的完整清單可以參考Output Formats疾捍。

expression

在 開發(fā)中奈辰,我們經(jīng)常會遇到這樣一種情況:我們設(shè)置一個視圖的背景顏色,運行后發(fā)現(xiàn)顏色不好看乱豆。嗯奖恰,好吧,在代碼里面修改一下宛裕,再編譯運行一下瑟啃,嗯,還是不好 看揩尸,然后再修改吧~~這樣無形中浪費了我們大把的時間蛹屿。在這種情況下,expression命令強大的功能就能體現(xiàn)出來了岩榆,它不僅會改變調(diào)試器中的值错负,還 改變了程序中的實際值。我們先來看看實際效果勇边,如下所示:

1

2

3

4

5(lldb)?exp?a?=?10

(NSInteger)?$0?=?10

(lldb)?exp?b?=?100

(NSInteger)?$1?=?100

2015-01-25?14:00:41.313?test[18064:71466]?a?+?b?=?110,?abc

expression命令的功能不僅于此犹撒,正如上面的po命令,其實際也是”expression -O —“命令的別名粒褒。更詳細使用可以參考Evaluating Expressions识颊。

image

image命令的用法也挺多,首先可以用它來查看工程中使用的庫奕坟,如下所示:

1

2

3

4

5

6

7

8

9(lldb)?image?list

[??0]?432A6EBF-B9D2-3850-BCB2-821B9E62B1E0?0x0000000100000000?/Users/**/Library/Developer/Xcode/DerivedData/test-byjqwkhxixddxudlnvqhrfughkra/Build/Products/Debug/test

[??1]?65DCCB06-339C-3E25-9702-600A28291D0E?0x00007fff5fc00000?/usr/lib/dyld

[??2]?E3746EDD-DFB1-3ECB-88ED-A91AC0EF3AAA?0x00007fff8d324000?/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation

[??3]?759E155D-BC42-3D4E-869B-6F57D477177C?0x00007fff8869f000?/usr/lib/libobjc.A.dylib

[??4]?5C161F1A-93BA-3221-A31D-F86222005B1B?0x00007fff8c75c000?/usr/lib/libSystem.B.dylib

[??5]?CBD1591C-405E-376E-87E9-B264610EBF49?0x00007fff8df0d000?/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation

[??6]?A260789B-D4D8-316A-9490-254767B8A5F1?0x00007fff8de36000?/usr/lib/libauto.dylib

......

我們還可以用它來查找可執(zhí)行文件或共享庫的原始地址祥款,這一點還是很有用的,當我們的程序崩潰時执赡,我們可以使用這條命令來查找崩潰所在的具體位置镰踏,如下所示:

1

2NSArray?*array?=?@[@1,?@2];

NSLog(@"item?3:?%@",?array[2]);

這段代碼在運行后會拋出如下異常:

1

2

3

4

5

6

7

8

9

102015-01-25?14:12:01.007?test[18122:76474]?***?Terminating?app?due?to?uncaught?exception'NSRangeException',?reason:'***?-[__NSArrayI?objectAtIndex:]:?index?2?beyond?bounds?[0?..?1]'

***?Firstthrowcall?stack:

(

0???CoreFoundation??????????????????????0x00007fff8e06f66c?__exceptionPreprocess?+?172

1???libobjc.A.dylib?????????????????????0x00007fff886ad76e?objc_exception_throw?+?43

2???CoreFoundation??????????????????????0x00007fff8df487de?-[__NSArrayI?objectAtIndex:]?+?190

3???test????????????????????????????????0x0000000100000de0?main?+?384

4???libdyld.dylib???????????????????????0x00007fff8f1b65c9?start?+?1

)

libc++abi.dylib:?terminatingwithuncaught?exception?of?type?NSException

根據(jù)以上信息,我們可以判斷崩潰位置是在main.m文件中沙合,要想知道具體在哪一行奠伪,可以使用以下命令:

1

2

3(lldb)?image?lookup?--address?0x0000000100000de0

Address:?test[0x0000000100000de0]?(test.__TEXT.__text?+?384)

Summary:?test`main?+?384?at?main.m:23

可以看到跌帐,最后定位到了main.m文件的第23行,正是我們代碼所在的位置绊率。

我們還可以使用image lookup命令來查看具體的類型谨敛,如下所示:

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?--type?NSURL

Best?match?foundin/Users/**/Library/Developer/Xcode/DerivedData/test-byjqwkhxixddxudlnvqhrfughkra/Build/Products/Debug/test:

id?=?{0x100000157},?name?="NSURL",?byte-size?=?40,?decl?=?NSURL.h:17,?clang_type?=?"@interface?NSURL?:?NSObject{

NSString?*?_urlString;

NSURL?*?_baseURL;

void?*?_clients;

void?*?_reserved;

}

@property?(?readonly,getter?=?absoluteString,setter?=?,nonatomic?)?NSString?*?absoluteString;

@property?(?readonly,getter?=?relativeString,setter?=?,nonatomic?)?NSString?*?relativeString;

@property?(?readonly,getter?=?baseURL,setter?=?,nonatomic?)?NSURL?*?baseURL;

@property?(?readonly,getter?=?absoluteURL,setter?=?,nonatomic?)?NSURL?*?absoluteURL;

@property?(?readonly,getter?=?scheme,setter?=?,nonatomic?)?NSString?*?scheme;

@property?(?readonly,getter?=?resourceSpecifier,setter?=?,nonatomic?)?NSString?*?resourceSpecifier;

@property?(?readonly,getter?=?host,setter?=?,nonatomic?)?NSString?*?host;

@property?(?readonly,getter?=?port,setter?=?,nonatomic?)?NSNumber?*?port;

@property?(?readonly,getter?=?user,setter?=?,nonatomic?)?NSString?*?user;

@property?(?readonly,getter?=?password,setter?=?,nonatomic?)?NSString?*?password;

@property?(?readonly,getter?=?path,setter?=?,nonatomic?)?NSString?*?path;

@property?(?readonly,getter?=?fragment,setter?=?,nonatomic?)?NSString?*?fragment;

@property?(?readonly,getter?=?parameterString,setter?=?,nonatomic?)?NSString?*?parameterString;

@property?(?readonly,getter?=?query,setter?=?,nonatomic?)?NSString?*?query;

@property?(?readonly,getter?=?relativePath,setter?=?,nonatomic?)?NSString?*?relativePath;

@property?(?readonly,getter?=?fileSystemRepresentation,setter?=??)?const?char?*?fileSystemRepresentation;

@property?(?readonly,getter?=?isFileURL,setter?=?,readwrite?)?BOOL?fileURL;

@property?(?readonly,getter?=?standardizedURL,setter?=?,nonatomic?)?NSURL?*?standardizedURL;

@property?(?readonly,getter?=?filePathURL,setter?=?,nonatomic?)?NSURL?*?filePathURL;

@end"

可以看到,輸出結(jié)果中列出了NSURL的一些成員變量及屬性信息滤否。

image命令還有許多其它功能脸狸,具體可以參考Executable and Shared Library Query Commands

流程控制

流程控制的命令實際上我們在上一小節(jié)已經(jīng)講過了藐俺,在Xcode的控制面板中同樣可以使用這些命令炊甲,在此不在重復。

命令別名及幫助系統(tǒng)

LLDB有兩個非常有用的特性欲芹,即命令別名及幫助卿啡。

命令別名

我們可以使用LLDB的別名機制來為常用的命令創(chuàng)建一個別名,以方便我們的使用菱父,如下命令:

1

(lldb)?breakpoint?set?--file?foo.c?--line?12

如果在我們的調(diào)試中需要經(jīng)常用到這條命令颈娜,則每次輸入這么一長串的字符一定會很讓人抓狂。此時浙宜,我們就可以為這條命令創(chuàng)建一個別名官辽,如下所示:

1

(lldb)?command?alias?bfl?breakpoint?set?-f?%1?-l?%2

這樣,我們只需要按如下方式來使用它即可:

1

(lldb)?bfl?foo.c?12

是不是簡單多了粟瞬?

我 們可以自由地創(chuàng)建LLDB命令的別名集合同仆。LLDB在啟動時會讀取~/.lldbinit文件。這個文件中存儲了command alias命令創(chuàng)建的別名裙品。LLDB幫助系統(tǒng)會讀取這個初始化文件并會列出這些別名乓梨,以讓我們了解自己所設(shè)置的別名。我們可以使用”help -a”命令并在輸出的后面來查看這邊別名清酥,其以下面這行開始:

1

2...

The?following?is?a?list?of?your?current?command?abbreviations?(see'help?command?alias'formore?info):?...

如果我們不喜歡已有命令的別名扶镀,則可以使用以下命令來取消這個別名:

1

(lldb)?command?unalias?b

幫助系統(tǒng)

LLDB幫助系統(tǒng)讓我們可以了解LLDB提供了哪些功能,并可以查看LLDB命令結(jié)構(gòu)的詳細信息焰轻。熟悉幫助系統(tǒng)可以讓我們訪問幫助系統(tǒng)中中命令文檔臭觉。

我們可以簡單地調(diào)用help命令來列出LLDB所有的頂層命令。如下所示:

1

2

3

4

5

6

7

8

9

10

11

12(lldb)?help

The?following?is?a?list?of?built-in,?permanent?debugger?commands:

_regexp-attach????--?Attach?to?a?process?idifindecimal,?otherwise?treat?the

argument?as?a?process?name?to?attach?to.

_regexp-break--?Set?a?breakpoint?using?a?regular?expression?to?specify?the

location,?where??isindecimal?and??is

inhex.

_regexp-bt????????--?Show?a?backtrace.??An?optional?argument?is?accepted;if

that?argument?is?a?number,?it?specifies?the?number?of

frames?to?display.??If?that?argument?is'all',?full

backtraces?of?all?threads?are?displayed.

…?and?so?forth?…

如果help后面跟著某個特定的命令辱志,則會列出該命令相關(guān)的所有信息蝠筑,我們以breakpoint set為例,輸出信息如下:

1

2

3

4

5

6

7

8

9(lldb)?help?breakpoint?set

Sets?a?breakpoint?or?set?of?breakpointsinthe?executable.

Syntax:?breakpoint?set?

Command?Options?Usage:

breakpoint?set?[-Ho]?-l??[-s?]?[-i?]?[-c?]?[-x?]?[-t?]?[-T?]?[-q?]?[-f?]?[-K?]

breakpoint?set?[-Ho]?-a??[-s?]?[-i?]?[-c?]?[-x?]?[-t?]?[-T?]?[-q?]

breakpoint?set?[-Ho]?-n??[-s?]?[-i?]?[-c?]?[-x?]?[-t?]?[-T?]?[-q?]?[-f?]?[-K?]?[-L?]

breakpoint?set?[-Ho]?-F??[-s?]?[-i?]?[-c?]?[-x?]?[-t?]?[-T?]?[-q?]?[-f?]?[-K?]

…?and?so?forth?…

還有一種更直接的方式來查看LLDB有哪些功能揩懒,即使用apropos命令:它會根據(jù)關(guān)鍵字來搜索LLDB幫助文檔什乙,并為每個命令選取一個幫助字符串,我們以apropos file為例已球,其輸出如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19(lldb)?apropos?file

The?following?commands?may?relate?to'file':

log?enable?????????????????????--?Enable?loggingfora?single?log?channel.

memory?read????????????????????--?Read?from?the?memory?of?the?process?being

debugged.

memory?write???????????????????--?Write?to?the?memory?of?the?process?being

debugged.

platform?process?launch????????--?Launch?anewprocess?on?a?remote?platform.

platform?select????????????????--?Create?a?platformifneeded?and?select?it?as

the?current?platform.

plugin?load????????????????????--?Import?a?dylib?that?implements?an?LLDB

plugin.

process?launch?????????????????--?Launch?the?executableinthe?debugger.

process?load???????????????????--?Load?a?shared?library?into?the?current

process.

source?????????????????????????--?A?set?of?commandsforaccessing?source?file

information

…?and?so?forth?…

我們還可以使用help來了解一個命令別名的構(gòu)成臣镣。如:

1

2

3(lldb)?help?b

'b'is?an?abbreviationfor'_regexp-break'

help命令的另一個特性是可以查看某個具體參數(shù)的使用辅愿,我們以”break command add”命令為例:

1

2

3

4(lldb)?helpbreakcommand?add

Add?a?set?of?commands?to?a?breakpoint,?to?be?executed?whenever?the?breakpoint?is?hit.

Syntax:?breakpoint?command?add??

etc...

如果想了解以上輸出的參數(shù)的作用,我們可以在help后面直接指定這個參數(shù)(將其放在尖括號內(nèi))來查詢它的詳細信息忆某,如下所示:

1

2

3(lldb)?help?

?--?Breakpoint?IDs?consist?major?and?minor?numbers;?the?major

etc...

幫助系統(tǒng)能讓我們快速地了解一個LLDB命令的使用方法点待。經(jīng)常使用它,可以讓我們更快地熟悉LLDB的各項功能弃舒,所以建議多使用它癞埠。

總結(jié)

LLDB 帶給我們強大的調(diào)試功能,在調(diào)試過程中充分地利用它可以幫助我們極大地提高調(diào)試效率聋呢。我們可以不用寫那么多的NSLog來打印一大堆的日志苗踪。所以建議在日 常工作中多去使用它。當然削锰,上面的命令只是LLDB的冰山一角徒探,更多的使用還需要大家自己去發(fā)掘,在此只是拋磚引玉喂窟,做了一些整理。

參考

The LLDB Debugger

LLDB Quick Start Guide

與調(diào)試器共舞 – LLDB 的華爾茲

LLDB調(diào)試命令初探

NSLog效率低下的原因及嘗試lldb斷點打印Log

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末央串,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淑履,老刑警劉巖棱诱,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異饲宿,居然都是意外死亡厦酬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門瘫想,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仗阅,“玉大人,你說我怎么就攤上這事国夜〖踉耄” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵车吹,是天一觀的道長筹裕。 經(jīng)常有香客問我,道長窄驹,這世上最難降的妖魔是什么朝卒? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮乐埠,結(jié)果婚禮上抗斤,老公的妹妹穿的比我還像新娘囚企。我一直安慰自己,他們只是感情好豪治,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布洞拨。 她就那樣靜靜地躺著,像睡著了一般负拟。 火紅的嫁衣襯著肌膚如雪烦衣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天掩浙,我揣著相機與錄音花吟,去河邊找鬼。 笑死厨姚,一個胖子當著我的面吹牛衅澈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谬墙,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼今布,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拭抬?” 一聲冷哼從身側(cè)響起部默,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎造虎,沒想到半個月后傅蹂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡算凿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年份蝴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氓轰。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡婚夫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出署鸡,到底是詐尸還是另有隱情请敦,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布储玫,位于F島的核電站侍筛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撒穷。R本人自食惡果不足惜匣椰,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望端礼。 院中可真熱鬧禽笑,春花似錦入录、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蟀伸,卻和暖如春蚀同,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啊掏。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工蠢络, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人迟蜜。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓刹孔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親娜睛。 傳聞我的和親對象是個殘疾皇子髓霞,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • [轉(zhuǎn)]淺談LLDB調(diào)試器文章來源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc閱讀 2,498評論 2 6
  • LLDB的Xcode默認的調(diào)試器,它與LLVM編譯器一起畦戒,帶給我們更豐富的流程控制和數(shù)據(jù)檢測的調(diào)試功能方库。平時用Xc...
    CoderSC閱讀 1,355評論 0 2
  • 轉(zhuǎn)載 與調(diào)試器共舞 - LLDB 的華爾茲: https://objccn.io/issue-19-2/ 推薦:i...
    F麥子閱讀 3,332評論 0 10
  • LLDB的Xcode默認的調(diào)試器,它與LLVM編譯器一起兢交,帶給我們更豐富的流程控制和數(shù)據(jù)檢測的調(diào)試功能。平時用Xc...
    小笨狼閱讀 20,463評論 31 187
  • 你有沒有一瞬間笼痹,覺得一切不外如此配喳,全部荒唐可笑
    袁小麻閱讀 214評論 0 1