LLDB-iOS高效開發(fā)必備利器詳解

LLDB

一、什么是lldb

lldb官網(wǎng)文檔地址:https://lldb.llvm.org/

LLDB is a next generation, high-performance debugger. It is built as a set of reusable components which highly leverage existing libraries in the larger LLVM Project, such as the Clang expression parser and LLVM disassembler.

LLDB is the default debugger in Xcode on macOS and supports debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.

lldb是一個高效的debug工具停忿。在大型的LLVM工程中些楣,lldb作為一個可重復(fù)使用的組件庫被使用绩卤,例如作為Clang 解析器或者用于LLVM 反匯編使用。

lldb 是默認(rèn)被嵌入的Xcode IDE中的,使用Xcode 開發(fā)過程中默認(rèn)支持LLDB調(diào)試的备蚓,其支持 C、C++囱稽、OC語言郊尝,同時支持了真機和模擬器。

lldb 支持以下平臺:

  • macOS debugging for i386, x86_64 and AArch64

  • iOS, tvOS, and watchOS simulator debugging on i386, x86_64 and AArch64

  • iOS, tvOS, and watchOS device debugging on ARM and AArch64

  • Linux user-space debugging for i386, x86_64, ARM, AArch64, MIPS64, PPC64le, s390x

  • FreeBSD user-space debugging for i386, x86_64, ARM, AArch64, MIPS64, PPC

  • NetBSD user-space debugging for i386 and x86_64

  • Windows user-space debugging for i386, x86_64, ARM and AArch64 (*)

    下面的內(nèi)容講解是在ios平臺做的內(nèi)容測試战惊,其他平臺沒做探究流昏。

在上述介紹了lldb的概念提到了LLVM 和Clang解析器,詳細(xì)了解下這兩個名詞。

LLVM:LLVM是構(gòu)架編譯器(compiler)的框架系統(tǒng)况凉,以C++編寫而成谚鄙,用于優(yōu)化以任意程序語言編寫的程序的編譯時間(compile-time)、鏈接時間(link-time)刁绒、運行時間(run-time)以及空閑時間(idle-time)闷营,對開發(fā)者保持開放,并兼容已有腳本知市。

----百度百科

LLVM計劃啟動于2000年傻盟,最初由美國UIUC大學(xué)的Chris Lattner博士主持開展。2006年Chris Lattner加盟Apple Inc.并致力于LLVM在Apple開發(fā)體系中的應(yīng)用嫂丙。Chris Lattner 同時是Swift創(chuàng)造者娘赴。

LLVM的使用

開發(fā)硬件平臺 Windows Linux Mac OS
在Windows上可以使用Mingw編譯LLVM
也可以用VisualStudio 編譯 GCC編譯或者是以LLVM/Clang編譯 Xcode自帶

傳統(tǒng)的編譯器架構(gòu)

傳統(tǒng)編譯器架構(gòu)圖.jpeg

  1. Frontend:前端

    前端:詞法分析、語法分析跟啤、語義分析诽表、生成中間代碼

  2. Optimizer:優(yōu)化器

    優(yōu)化器:中間代碼優(yōu)化

  3. Backend:后端

    后端:生成機目標(biāo)器碼

LLVM編譯器架構(gòu)

LLVM架構(gòu)圖.png

從LLVM架構(gòu)圖我們可以看出這種架構(gòu)方案的高明之處。

  • 使用統(tǒng)一的中間代碼LLVM IR(LLVM Intermediate Representation)
  • 高擴展性:無論是增加一種新的語言腥光,還是新增加了一種新的設(shè)備关顷,中間優(yōu)化器不用做修改,只需要增加一種新的前端和后端即可
  • LLVM目前被作為實現(xiàn)各種靜態(tài)和運行時編譯語言的通用基礎(chǔ)結(jié)構(gòu)(GCC家族武福、Java议双、.NET、Python捉片、Ruby平痰、Scheme、Haskell伍纫、D等)

明白LLVM之后 那Clang 又是起什么作用呢宗雇?

Clang是一個由Apple主導(dǎo)編寫,基于LLVM的C/C++/Objective-C編譯器

從上面的介紹我們可以看出其實Clang 是基于LLVM框架針對C/C++/Objective-C語言開發(fā)出來的一個編譯器莹规,不具備通用性和不可移植性赔蒲。

相比于GCC,Clang具有如下優(yōu)點

  • 編譯速度快:在某些平臺上良漱,Clang的編譯速度顯著的快過GCC(Debug模式下編譯OC速度比GGC快3倍)
  • 占用內(nèi)存小:Clang生成的AST所占用的內(nèi)存是GCC的五分之一左右
  • 模塊化設(shè)計:Clang采用基于庫的模塊化設(shè)計舞虱,易于 IDE 集成及其他用途的重用
  • 診斷信息可讀性強:在編譯過程中,Clang 創(chuàng)建并保留了大量詳細(xì)的元數(shù)據(jù) (metadata)母市,有利于調(diào)試和錯誤報告
  • 設(shè)計清晰簡單矾兜,容易理解,易于擴展增強

Clang與LLVM關(guān)系

Clang與LLVM.png

Clang與LLVM

LLVM整體架構(gòu)患久,前端用的是clang椅寺,廣義的LLVM是指整個LLVM架構(gòu)浑槽,一般狹義的LLVM指的是LLVM后端(包含代碼優(yōu)化和目標(biāo)代碼生成)。

源代碼(c/c++)經(jīng)過clang–> 中間代碼(經(jīng)過一系列的優(yōu)化返帕,優(yōu)化用的是Pass) --> 機器碼

二桐玻、 lldb調(diào)試案例

查看lldb調(diào)試都支持哪些指令呢?我們可以通過 help 來查找


截屏20210620 下午7.37.32.png

這里只粘貼了部分命令溉旋,還有很多命令可支持畸冲。

下面介紹幾個常用的指令:

  • expression : 調(diào)試過程中修改值 嫉髓,可用 e 代替观腊。
    截屏20210620 下午7.42.08.png

還可以調(diào)用方法 :(lldb) expression [self testAA] 等同于call的功能

還可以輸入命令:所以 expression 的指令包含了p&call的集合

po = **e -O – **

案例修改view顏色

(lldb) po self.view
<UIView: 0x600034cfbe90; frame = (0 0; 844 390); autoresize = W+H; layer = <CALayer: 0x600034cfffe0>>

(lldb) e id $myView = (id)0x600034cfbe90
(lldb) e (void)[$myView setBackgroundColor:[UIColor blueColor]]

  • **p/po **: 輸出(print的簡寫)
截屏20210620 下午11.27.29.png
截屏20210620 下午7.49.19.png

可以看出p 和po都是輸出內(nèi)容的命令,區(qū)別是

p 輸出包含了數(shù)據(jù)類型,object類型輸出的是對象的指針地址+對象類型,基本類型輸出的是 基本類型+值

po輸出的是值

(lldb) p name
(NSString *) $0 = 0x000000010d2e2410
(lldb) po name
miqiyy

這里的 2* 是lldb語法累加的結(jié)果算行,從 *0 表示p/po第一條輸出梧油,$2表示 第三條輸出

p還能控制輸出的格式類型: p/

(lldb) po/t 16
0b00000000000000000000000000010000

(lldb) po/x 16
0x00000010

  • c、n州邢、s 代替continue儡陨,step over,step into量淌,step out

    c = coutinue :直接跳過 改 斷點

    n = step over:一步步跟蹤

    s = step into:調(diào)入方法內(nèi)

    當(dāng)我們不經(jīng)意見進(jìn)入一個本不想進(jìn)入的方法內(nèi)骗村,可以點擊 step out 直接跳出 返回到 調(diào)用位置

  • thread return [可選的返回參數(shù)]

thread return 繞過方法的真正執(zhí)行,偽造返回值

斷點相關(guān)

  • br list:顯示工程中所有的斷點

    (lldb) br list
    Current breakpoints:
    1: file = '/Users/xianliangdev/Desktop/LearniOS/LearniOS/ViewController.m', line = 60, exact_match = 0, locations = 1, resolved = 1, hit count = 1
    
      1.1: where = LearniOSA`-[ViewController btnAction] + 123 at ViewController.m:60:17, address = 0x0000000108662d3b, resolved, hit count = 1 
    
    5: file = '/Users/xianliangdev/Desktop/LearniOS/LearniOS/ViewController.m', line = 74, exact_match = 0, locations = 1, resolved = 1, hit count = 0
    
      5.1: where = LearniOSA`-[ViewController testBB] + 23 at ViewController.m:74:9, address = 0x0000000108662e87, resolved, hit count = 0 
    
    
  • br disable/enable<breakpointid style="box-sizing: border-box; margin: 0px; padding: 0px;"></breakpointid>

    (lldb) br disable 1
    1 breakpoints disabled.
    (lldb) br list
    Current breakpoints:
    1: file = '/Users/xianliangdev/Desktop/LearniOS/LearniOS/ViewController.m', line = 60, exact_match = 0, locations = 1 Options: disabled 
    
    1.1: where = LearniOSA`-[ViewController btnAction] + 123 at ViewController.m:60:17, address = 0x0000000108662d3b, unresolved, hit count = 1 
      (lldb) br enable 1
    1 breakpoints enabled.
    
    
  • *br set -f .m -l

    br delete<breakpointid style="box-sizing: border-box; margin: 0px; padding: 0px;"></breakpointid>

    用命令下斷點/刪除斷點 呀枢。

    <note style="box-sizing: border-box; margin: 0px; padding: 0px;">不過開發(fā)過程中還是不用這樣做胚股,br set 斷點后 沒有標(biāo)識 ,最后調(diào)試過程比較麻煩 不能肉眼觀察 都有哪些斷點了</note>

  • 在調(diào)試過程中仍然繼續(xù)執(zhí)行 渲染服務(wù)裙秋,渲染服務(wù)實際上是一個另外的進(jìn)程 (被稱作 backboardd)琅拌。

    e (void)[CATransaction flush]

  • bt all :打印當(dāng)前運行的所有線程 運行信息

    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
      * frame #0: 0x000000010dbe2c39 LearniOSA`-[ViewController btnAction](self=0x00007faba2c09c10, _cmd="btnAction") at ViewController.m:66:17
        frame #1: 0x0000000111eb0937 UIKitCore`-[UIApplication sendAction:to:from:forEvent:] + 83
        frame #2: 0x00000001117d145d UIKitCore`-[UIControl sendAction:to:forEvent:] + 223
        frame #3: 0x00000001117d1780 UIKitCore`-[UIControl _sendActionsForEvents:withEvent:] + 332
        frame #4: 0x00000001117d007f UIKitCore`-[UIControl touchesEnded:withEvent:] + 500
        frame #5: 0x0000000111eecd01 UIKitCore`-[UIWindow _sendTouchesForEvent:] + 1287
        frame #6: 0x0000000111eeeb8c UIKitCore`-[UIWindow sendEvent:] + 4792
        frame #7: 0x0000000111ec8c89 UIKitCore`-[UIApplication sendEvent:] + 596
        frame #8: 0x0000000111f5b7ba UIKitCore`__processEventQueue + 17124
        frame #9: 0x0000000111f51560 UIKitCore`__eventFetcherSourceCallback + 104
        frame #10: 0x000000010e886ede CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
        frame #11: 0x000000010e886dd6 CoreFoundation`__CFRunLoopDoSource0 + 180
        frame #12: 0x000000010e88629e CoreFoundation`__CFRunLoopDoSources0 + 242
        frame #13: 0x000000010e8809f7 CoreFoundation`__CFRunLoopRun + 875
        frame #14: 0x000000010e8801a7 CoreFoundation`CFRunLoopRunSpecific + 567
        frame #15: 0x000000011a483d85 GraphicsServices`GSEventRunModal + 139
        frame #16: 0x0000000111eaa4df UIKitCore`-[UIApplication _run] + 912
        frame #17: 0x0000000111eaf39c UIKitCore`UIApplicationMain + 101
        frame #18: 0x000000010dbe4ca2 LearniOSA`main(argc=1, argv=0x00007ffee201fc60) at main.m:17:12
        frame #19: 0x000000010fc81bbd libdyld.dylib`start + 1
      thread #3
        frame #0: 0x000000011003c53e libsystem_kernel.dylib`__workq_kernreturn + 10
        frame #1: 0x00000001100bd4fd libsystem_pthread.dylib`_pthread_wqthread + 414
        frame #2: 0x00000001100bc467 libsystem_pthread.dylib`start_wqthread + 15
      thread #6, name = 'com.apple.uikit.eventfetch-thread'
        frame #0: 0x000000011003ae7e libsystem_kernel.dylib`mach_msg_trap + 10
        frame #1: 0x000000011003b1f0 libsystem_kernel.dylib`mach_msg + 60
        frame #2: 0x000000010e8864f9 CoreFoundation`__CFRunLoopServiceMachPort + 316
        frame #3: 0x000000010e880b9c CoreFoundation`__CFRunLoopRun + 1296
        frame #4: 0x000000010e8801a7 CoreFoundation`CFRunLoopRunSpecific + 567
        frame #5: 0x000000010df76204 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 209
        frame #6: 0x000000010df76473 Foundation`-[NSRunLoop(NSRunLoop) runUntilDate:] + 72
        frame #7: 0x0000000111f62ccd UIKitCore`-[UIEventFetcher threadMain] + 464
        frame #8: 0x000000010df9e8a9 Foundation`__NSThread__start__ + 1068
        frame #9: 0x00000001100c0950 libsystem_pthread.dylib`_pthread_start + 224
        frame #10: 0x00000001100bc47b libsystem_pthread.dylib`thread_start + 15
    
    
  • thread all: 展示當(dāng)前的所有線程列表

    (lldb) thread list
    Process 6862 stopped
    * thread #1: tid = 0x67140, 0x00000001055aebf9 LearniOSA`-[ViewController btnAction](self=0x00007fe214008aa0, _cmd="btnAction") at ViewController.m:63:28, queue = 'com.apple.main-thread', stop reason = step over
      thread #2: tid = 0x67c9d, 0x00000001078ef53e libsystem_kernel.dylib`__workq_kernreturn + 10
      thread #6: tid = 0x67cc4, 0x00000001078ede7e libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
    
    
  • image lookup

    1. image lookup -name 簡寫 image lookup -n 這個命令在開發(fā)過程中 還是比較常用的一個指令,

      常用來使用的范圍:

      一摘刑、方法的信息:如例子展示了方法btnAction 都在哪些類中實現(xiàn),并且列出了在對應(yīng)文件的位置

      2 matches found in /Users/xianliangdev/Library/Developer/Xcode/DerivedData/LearniOS-fpcguxeksnmswvcyseiyshympabj/Build/Products/Debug-iphonesimulator/LearniOSA.app/LearniOSA:
            Address: LearniOSA[0x0000000100004bb0] (LearniOSA.__TEXT.__text + 3904)
            Summary: LearniOSA`-[ViewController btnAction] at ViewController.m:59        Address: LearniOSA[0x0000000100006bb0] (LearniOSA.__TEXT.__text + 12096)
            Summary: LearniOSA`-[Person btnAction] at Person.m:19
      
      

      二进宝、 查找方法的實現(xiàn),特別是在引入三方sdk中 category 引用了同一個方法的實現(xiàn)枷恕,這是災(zāi)難性的 可能是因此引入一些bug

    2. image lookup -adress 簡寫 image lookup -a:如下例子 數(shù)組越界crash

      2021-06-27 23:00:16.056032+0800 LearniOSA[7276:457801] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** __boundsFail: index 4 beyond bounds [0 .. 2]'
      *** First throw call stack:
      (
          0   CoreFoundation                      0x000000010f575fba __exceptionPreprocess + 242
          1   libobjc.A.dylib                     0x000000010f41fff5 objc_exception_throw + 48
          2   CoreFoundation                      0x000000010f5f4523 _CFThrowFormattedException + 194
          3   CoreFoundation                      0x000000010f5fc2c4 -[__NSArrayI getObjects:range:].cold.1 + 0
          4   CoreFoundation                      0x000000010f59758e -[__NSArrayI objectAtIndex:] + 38
          5   LearniOSA                           0x000000010ebea5ee -[ViewController btnAction] + 321
          **
      )
      libc++abi: terminating with uncaught exception of type NSException
      *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** __boundsFail: index 4 beyond bounds [0 .. 2]'
      terminating with uncaught exception of type NSException
      CoreSimulator 757.5 - Device: iPhone 12 (AE147971-403C-4E70-A47A-42DAC6A13884) - Runtime: iOS 14.5 (18E182) - DeviceType: iPhone 12
      (lldb) image lookup -a 0x000000010ebea5ee
      LearniOSA was compiled with optimization - stepping may behave oddly; variables may not be available.
            Address: LearniOSA[0x00000001000025ee] (LearniOSA.__TEXT.__text + 2500)
            Summary: LearniOSA`-[ViewController btnAction] + 321 at ViewController.m:70:26
      
      
    3. image lookup -type <類型> 簡寫 image lookup -t <類型>

      (lldb) image lookup -type Person
      Best match found in /Users/xianliangdev/Library/Developer/Xcode/DerivedData/LearniOS-fpcguxeksnmswvcyseiyshympabj/Build/Products/Release-iphonesimulator/LearniOSA.app/LearniOSA:
      id = {0x7fffffff0004bd90}, name = "Person", byte-size = 16, decl = Person.h:13, compiler_type = "@interface Person : NSObject{
          (anonymous struct) mySelf;
          char _my;
      }
      @end"
      
      
三党晋、LLDB 和Python

lldb支持引入 腳本

(lldb) script import os
(lldb) script os.system("open http://www.objc.io/")
0

通過引入python 直接打開了鏈接

這樣就允許你創(chuàng)造各種酷的命令。把下面的語句放到文件 ~/myCommands.py 中:

<pre style="font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-indent: 0px; text-transform: none; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; margin: 0px 0px 16px; overflow-wrap: normal; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; line-height: 1.45; overflow: scroll; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; width: 754px; font-variant-ligatures: normal; orphans: 2; text-align: left; widows: 2; text-decoration-thickness: initial; padding: 0px !important; white-space: pre-wrap !important; color: rgb(34, 34, 34) !important;">

def caflushCommand(debugger, command, result, internal_dict): debugger.HandleCommand("e (void)[CATransaction flush]")

</pre>

然后再 LLDB 中運行:

command script import ~/myCommands.py

參考資料:

1徐块、LLVM:https://baike.baidu.com/item/LLVM/3598690?fr=aladdin

2未玻、Clang:https://baike.baidu.com/item/clang/3698345?fr=aladdin

3、理解LLVM:https://www.cnblogs.com/wuhh123/p/10668609.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛹锰,一起剝皮案震驚了整個濱河市深胳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铜犬,老刑警劉巖舞终,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轻庆,死亡現(xiàn)場離奇詭異,居然都是意外死亡敛劝,警方通過查閱死者的電腦和手機余爆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夸盟,“玉大人蛾方,你說我怎么就攤上這事∩仙拢” “怎么了桩砰?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長释簿。 經(jīng)常有香客問我亚隅,道長,這世上最難降的妖魔是什么庶溶? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任煮纵,我火速辦了婚禮,結(jié)果婚禮上偏螺,老公的妹妹穿的比我還像新娘行疏。我一直安慰自己,他們只是感情好套像,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布酿联。 她就那樣靜靜地躺著,像睡著了一般凉夯。 火紅的嫁衣襯著肌膚如雪货葬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天劲够,我揣著相機與錄音震桶,去河邊找鬼。 笑死征绎,一個胖子當(dāng)著我的面吹牛蹲姐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播人柿,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼柴墩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凫岖?” 一聲冷哼從身側(cè)響起江咳,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哥放,沒想到半個月后歼指,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爹土,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年踩身,在試婚紗的時候發(fā)現(xiàn)自己被綠了胀茵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡挟阻,死狀恐怖琼娘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情附鸽,我是刑警寧澤脱拼,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站拒炎,受9級特大地震影響挪拟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜击你,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谎柄。 院中可真熱鬧丁侄,春花似錦、人聲如沸朝巫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劈猿。三九已至拙吉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揪荣,已是汗流浹背筷黔。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仗颈,地道東北人佛舱。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像挨决,于是被迫代替她去往敵國和親请祖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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