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)
-
Frontend:前端
前端:詞法分析、語法分析跟啤、語義分析诽表、生成中間代碼
-
Optimizer:優(yōu)化器
優(yōu)化器:中間代碼優(yōu)化
-
Backend:后端
后端:生成機目標(biāo)器碼
LLVM編譯器架構(gòu)
從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
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 來查找
這里只粘貼了部分命令溉旋,還有很多命令可支持畸冲。
下面介紹幾個常用的指令:
-
expression : 調(diào)試過程中修改值 嫉髓,可用 e 代替观腊。
還可以調(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的簡寫)
可以看出p 和po都是輸出內(nèi)容的命令,區(qū)別是
p 輸出包含了數(shù)據(jù)類型,object類型輸出的是對象的指針地址+對象類型,基本類型輸出的是 基本類型+值
po輸出的是值
(lldb) p name
(NSString *) $0 = 0x000000010d2e2410
(lldb) po name
miqiyy
這里的 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
-
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
-
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
-
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