LLDB調試基本使用


  在平時開發中,我們可能需要調試某些東西,比如查看給服務器發請求時傳過去的參數,如果不適用LLDB的話我們用的最多的就是通過NSLog方式去打印,但現在我們可以精簡這個步驟,那就是使用LLDB調試命令.

  Xcode從4.0開始編譯器開始改用LLVM,相應的調試器也從gdb改為LLDB。而從 Xcode5.0開始所有工程也被自動設置為使用LLDB。

  使用:

  首先,我們需要先設置一個斷點;

  當程序執行到斷電的時候就會彈出LLDB調試面板:

  這個時候我們可以在這里輸入對應命令行回車查看或更改參數

po 指令可以用來打印一些對象或者字符串

出了打印參數信息外,還可以動態更改屬性值及其他功能,具體可以參照參考資料

 

 print、p:打印

 po:打印對象

 e:修改變量的值

n:運行至下一行

c:運行至下個斷點處(下面沒有斷點的話則繼續運行程序)

call:調用。其實上述p/po后接表達式(expression)也有調用的功能,一般只在不需要顯式輸出,或是無返回值時使用call,用於動態調試插入調用代碼。

例如可以在viewDidLoad:里面設置斷點,然后在程序中斷的時候輸入以下命令:

call [self.view setBackgroundColor:[UIColor redColor]];

image:可用於尋址(這個命令和圖片沒有任何關系)  這個功能很強大了  比如我們經常項目出現crash  控制台上就會打印下面的信息  這個時候我們可以根據這個信息來准確找到閃退位置(雖然閃退原因頭部寫的很清楚了  但是假如這個文件有很多setValueForKey方法呢,我們一個個找起來太費勁  我們就可以通過image來准確定位)

首先我們在上面信息中查找我們運行的程序的內存地址:也就是第4個 KVODemo對應的內存地址 0x00000001089faf99

然后在LLDB控制器面板輸入命令:image lookup --address 0x00000001089faf99 然后回車

就看到打印信息:

Address: KVODemo[0x0000000100001f99] (KVODemo.__TEXT.__text + 1113)
Summary: KVODemo`-[ViewController touchesBegan:withEvent:] + 265 at ViewController.m:126:5

Summary就會顯示哪個文件多少行   在ViewController.m文件的126行

 

bt(backtrace),打印當前調用堆棧(crash堆棧),“bt all”可打印所有thread的堆棧(相當於command+6的Debug Session Navigation)。

首先介紹一下什么叫調用堆棧:假設我們有幾個函數,分別是function1,function2,function3,funtion4,且function1調用function2,function2調用function3,function3調用function4。在function4運行過程中,我們可以從線程當前堆棧中了解到調用他的那幾個函數分別是誰。把函數的順序關系看,function4、function3、function2、function1呈現出一種“堆棧”的特征,最后被調用的函數出現在最上方。因此稱呼這種關系為調用堆棧(call stack)。

2.  作用

“調用堆棧”窗口可以查看當前堆棧上的函數或過程調用。
“調用堆棧”窗口顯示每個函數的名稱和編寫它所用的編程語言。函數或過程名可能伴隨有可選信息,如模塊名、行號、字節偏移量以及參數的名稱、類型和值。 可以打開或關閉這些可選信息的顯示。
一個黃色箭頭標識執行指針當前所位於的堆棧幀。 默認情況下,該幀的信息顯示在源、“反匯編”、“局部變量”、“監視”和“自動”窗口中。 如果想將上下文更改為堆棧上的另一個幀,可以在“調用堆棧”窗口中執行相應的操作。
當調試符號對部分調用堆棧不可用時,“調用堆棧”窗口也許就不能顯示那部分堆棧的正確信息。
 

常用的場景:

當故障發生時,如果程序被中斷,我們基本上只可以看到最后出錯的函數。

利用調用堆棧,我們可以知道當出錯函數被誰調用的時候出錯。這樣一層層的看上去,有時可以猜測出錯誤的原因。

 

讀取對象的內存地址:memory red ↓↓ 關於內存地址和對象本質的問題在底層文章中有所介紹

memory read/數量格式字節數  讀取對象/或某個具體的內存地址
(lldb) memory read/3xw ani
0x6000010893a0: 0x07ff3318 0x00000001 0x00000001
數量是指讀取從該對象起始地址或該內存地址起始地址后多長的地址
格式
x是16進制,f是浮點,d是10進制

字節大小
b:byte 1字節,h:half word 2字節
w:word 4字節,g:giant word 8字節

 

 

修改內存中的值
memory write 內存地址 數值↓↓↓

當我們讀取到對象的地址值是 就可以動態修改內存地址所指向數據的值  比如上圖中age屬性的地址值是0x6000010893a8開始后的四個字節 

(lldb)memory write 0x6000010893a8 5

我們再打印age的屬性值時  就變成了5

(lldb) p ani.age
(int) $18 = 5
(lldb) 

這個值的修改是真實有效的  並不是只存在於lldb面板中  在程序中都是有效的

 

 

frame:(這個frame並不是用來設置布局的frma 而是[幀] 也就是我們通過bt命令打印出來的調用堆棧)用於選擇和檢查當前線程堆棧幀的命令。

frame variable

平時Debug的時候我們經常做的事就是查看變量的值,通過frame variable命令,可以打印出當前frame[也就是斷點所在的方法]的所有變量

(lldb) frame variable
(ViewController *) self = 0x00007fc263c10930
(SEL) _cmd = "viewDidLoad"
(PersonClass *) person1 = 0x00006000012c8b10
(AnimalClass *) ani = 0x00006000010893a0
(PersonClass *) person2 = 0x00006000012cc4a0

frame info: 查看當前frame[當前斷點所在的方法]的信息

(lldb) frame info
frame #0: 0x0000000107fefdfa KVODemo`-[ViewController viewDidLoad](self=0x00007fc263c10930, _cmd="viewDidLoad") at ViewController.m:32:20

frame select: 選擇某個frame(不常用)  這里select 后面跟的數字就是通過bt打印出來的當前調用堆棧對應的frame數字

(lldb) frame select 1
frame #1: 0x000000010ba8f43b UIKitCore`-[UIViewController loadViewIfRequired] + 1183
UIKitCore`-[UIViewController loadViewIfRequired]:
->  0x10ba8f43b <+1183>: movl   (%r14), %eax
    0x10ba8f43e <+1186>: testl  %eax, %eax
    0x10ba8f440 <+1188>: je     0x10ba8f786               ; <+2026>
    0x10ba8f446 <+1194>: cmpl   $0x70000, %eax            ; imm = 0x70000 
(lldb) frame select 8
frame #8: 0x0000000114ef86d6 UIKitCore`__111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 904
UIKitCore`__111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke:
->  0x114ef86d6 <+904>: movq   (%rbx), %rdi
    0x114ef86d9 <+907>: movq   0x1442aa8(%rip), %rsi     ; "_calledRunWithMainScene"
    0x114ef86e0 <+914>: callq  *%r14
    0x114ef86e3 <+917>: movq   %r12, %rdi
(lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x000000010f602d58 KVODemo`-[ViewController viewDidLoad](self=0x00007faca36083e0, _cmd="viewDidLoad") at ViewController.m:25:25
    frame #1: 0x00000001150b243b UIKitCore`-[UIViewController loadViewIfRequired] + 1183
    frame #2: 0x00000001150b2868 UIKitCore`-[UIViewController view] + 27
    frame #3: 0x00000001156eac33 UIKitCore`-[UIWindow addRootViewControllerViewIfPossible] + 122
    frame #4: 0x00000001156eb327 UIKitCore`-[UIWindow _setHidden:forced:] + 289
    frame #5: 0x00000001156fdf86 UIKitCore`-[UIWindow makeKeyAndVisible] + 42
    frame #6: 0x00000001156adf1c UIKitCore`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4555
    frame #7: 0x00000001156b30c6 UIKitCore`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1617
  * frame #8: 0x0000000114ef86d6 UIKitCore`__111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 904
    frame #9: 0x0000000114f00fce UIKitCore`+[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
    frame #10: 0x0000000114ef82ec UIKitCore`-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 236
    frame #11: 0x0000000114ef8c48 UIKitCore`-[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1091
    frame #12: 0x0000000114ef6fba UIKitCore`__82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 782
    frame #13: 0x0000000114ef6c71 UIKitCore`-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 433
    frame #14: 0x0000000114efb9b6 UIKitCore`__125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 576
    frame #15: 0x0000000114efc610 UIKitCore`_performActionsWithDelayForTransitionContext + 100
    frame #16: 0x0000000114efb71d UIKitCore`-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 223
    frame #17: 0x0000000114f006d0 UIKitCore`-[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
    frame #18: 0x00000001156b19a8 UIKitCore`-[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 514
    frame #19: 0x0000000115268dfa UIKitCore`-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
    frame #20: 0x000000011bf9f125 FrontBoardServices`-[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
    frame #21: 0x000000011bfa8ed6 FrontBoardServices`__56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 283
    frame #22: 0x000000011bfa8700 FrontBoardServices`__40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
    frame #23: 0x00000001121a0db5 libdispatch.dylib`_dispatch_client_callout + 8
    frame #24: 0x00000001121a42ba libdispatch.dylib`_dispatch_block_invoke_direct + 300
    frame #25: 0x000000011bfda146 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
    frame #26: 0x000000011bfd9dfe FrontBoardServices`-[FBSSerialQueue _performNext] + 451
    frame #27: 0x000000011bfda393 FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 42
    frame #28: 0x000000011089dbe1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #29: 0x000000011089d463 CoreFoundation`__CFRunLoopDoSources0 + 243
    frame #30: 0x0000000110897b1f CoreFoundation`__CFRunLoopRun + 1231
    frame #31: 0x0000000110897302 CoreFoundation`CFRunLoopRunSpecific + 626
    frame #32: 0x0000000118ef82fe GraphicsServices`GSEventRunModal + 65
    frame #33: 0x00000001156b4ba2 UIKitCore`UIApplicationMain + 140
    frame #34: 0x000000010f603440 KVODemo`main(argc=1, argv=0x00007ffee05fbf08) at main.m:14:16
    frame #35: 0x0000000112215541 libdyld.dylib`start + 1
    frame #36: 0x0000000112215541 libdyld.dylib`start + 1

 

 

 

watchpoint:觀察變量或者屬性 這是一個非常有用的東西,我們經常遇到,某一個變量,不知道什么時候值被改掉了,就可以使用這個東西去定位:

watchpoint set variable self->_person1->_age

//注意 不能使用點語法

設置成功后會打印↓↓

(lldb) watchpoint set variable self->_person1->_age
Watchpoint created: Watchpoint 1: addr = 0x600001dbc948 size = 4 state = enabled type = w
    watchpoint spec = 'self->_person1->_age'
    new value: 1

這樣當self.person1.age的值發生改變時就對自動斷點  打印一下信息↓↓

Watchpoint 1 hit:
old value: 1
new value: 123

這個時候我們可以在左側調用堆棧中找到調用的方法

 

也可以繼續在控制器敲入bt:查看當前調用堆棧 找到對應的方法↓↓

 

 

這里只是介紹一些常用的 我們也可以在lldb調試面板中通過help指令來學習更多的功能↓↓

 

 

 

具體的命令行可以參考:

The LLDB Debugger 

 

參考資料

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM