iOS之LLDB常用調試命令

2021-02-14 swift

LLDB是個開源的內置於XCode的調試工具,這裡來理一理常用用法。
lldb對於命令的簡稱,是頭部匹配方式,只要不混淆,你可以隨意簡稱某個命令。結果為在xcode下驗證所得,可能與其它平臺有所誤差。

1 列印值、修改值、調用方法1.1 p、po 列印值

列印相關的命令有:p、po。
p 和 po 的區別在於使用 po 只會輸出對應的值,而 p 則會返回值的類型以及命令結果的引用名。

(lldb) p width(CGFloat) $10 = 70(lldb) po width70(lldb) p endTime(__NSCFString *) $14 = 0x0000608000437660 @"08-11 11:43"(lldb) po endTime08-11 11:43

對比結果:

po:輸出值
p:輸出值+值類型+引用名+內存地址(xcode中有內存地址,其它平臺不確定)
除此之外,p還隱藏了一個有意思的功能,常量的進位轉換:

//默認列印為10進位(lldb) p 100(int) $8 = 100//轉16進位(lldb) p/x 100(int) $9 = 0x00000064//轉8進位(lldb) p/o 100(int) $10 = 0144//轉二進位(lldb) p/t 100(int) $2 = 0b00000000000000000000000001100100//字符轉10進位數字(lldb) p/d 'A'(char) $7 = 65//10進位數字轉字符(lldb) p/c 66(int) $10 = B\0\0\0

1.2 expression 修改參數值

感覺exp命令是調試過程中最有價值有命令了,它可以列印值、修改值。

//expression列印值(lldb) expression width(CGFloat) $5 = 67//expression修改值(lldb) expression width = 80(CGFloat) $6 = 80//列印修改後結果(lldb) p width(CGFloat) $7 = 80(lldb)

expression:同樣可以輸出值+值類型+引用名,但其一般用於修改。

1.3 call 方法調用

在斷點調用某個方法,並輸出此方法的返回值。

(lldb) call width(CGFloat) $12 = 70(lldb) call endTime(__NSCFString *) $16 = 0x0000608000437660 @"08-11 11:43"

call:同樣為輸出值+值類型+引用名

2 Thread2.1 堆棧列印 thread backtrace

如果嫌堆棧列印太長,可以加一個值限制,如bt 10,只列印

(lldb) bt 10* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1  * frame #0: 0x00000001005e4906 DiDi`-[FW_HomeCell_HotBill setDataSource:](self=0x00007fd3938a7800, _cmd="setDataSource:", dataSource=0x00006080001c8bb0) at FW_HomeCell.m:357    frame #1: 0x00000001009a9fd7 DiDi`-[FW_MyHomeTableView tableView:cellForRowAtIndexPath:](self=0x00007fd3921fec00, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007fd3921fec00, indexPath=0xc000000000000316) at FW_MyHomeTableView.m:247    frame #2: 0x00000001055a2ab2 UIKit`-[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 750    frame #3: 0x00000001055a2cf8 UIKit`-[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74    frame #4: 0x0000000105577639 UIKit`-[UITableView _updateVisibleCellsNow:isRecursive:] + 2845    frame #5: 0x00000001055abccc UIKit`-[UITableView _performWithCachedTraitCollection:] + 111    frame #6: 0x0000000105592e7a UIKit`-[UITableView layoutSubviews] + 233    frame #7: 0x00000001054f955b UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268    frame #8: 0x0000000105114904 QuartzCore`-[CALayer layoutSublayers] + 146    frame #9: 0x0000000105108526 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 370

2.2 thread return 跳出當前方法的執行

Debug的時候,也許會因為各種原因,我們不想讓代碼執行某個方法,或者要直接返回一個想要的值。這時候就該thread return上場了。
有返回值的方法裡,如:numberOfSectionsInTableView:,直接thread return 10,就可以直接跳過方法執行,返回10.

//跳出方法(lldb) thread return//讓帶有返回int值的方法直接跳出,並返回值10(lldb) thread return 10

2.3 流程控制

實際上使用xcode自帶的可視化工具來控制「繼續」「暫停」「下一步」「進入」「跳出」更簡單

繼續:continue, c下一步:next, n進入:step, s跳出:finish, f

2.4 跳幀 frame select N

2.1中列印有10幀,如果我想跳轉到第1幀:frame select 1

(lldb) frame select 1frame #1: 0x0000000105e91c3c DiDi`-[FW_HomeViewController tableView:cellForRowAtIndexPath:](self=0x00007fbf9f73b410, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007fbfa11dc400, indexPath=0xc000000000a00316) at FW_HomeViewController.m:597   594                  break;   595                     596                  case 3: {-> 597                      cell.[4md[0mataSource = _hotBills[indexPath.row];   598                      cell.textSelect = ^(UITextField *text) {   599                          weakSelf.curruntText = text;   600                      };

2.5 查看幀變量 frame variable

(lldb) frame variable(FW_HomeViewController *) self = 0x00007faccbf587d0(SEL) _cmd = "tableView:cellForRowAtIndexPath:"(UITableView *) tableView = 0x00007faccd09b400(NSIndexPath *) indexPath = 0xc000000000000316(FW_HomeViewController *) weakSelf = 0x00007faccbf587d0(FW_HomeCell_HotBill *) cell = 0x00007faccc101a00(UIView *) model = 0x00007fff52c13d90(FW_HomeCell_HotBill *) billCell = 0x00000001124e99f6

3 Image3.1 image lookup -address 查找崩潰位置

當你遇見數組崩潰,你又沒有找到崩潰的位置,只扔給你一堆報錯信息,這時候image lookup來幫助你。如下

0   CoreFoundation                      0x0000000103209b0b __exceptionPreprocess + 171    1   libobjc.A.dylib                     0x00000001079db141 objc_exception_throw + 48    2   CoreFoundation                      0x000000010313effb -[__NSArrayM objectAtIndex:] + 203    3   DiDi                                0x00000001009a9f3a -[FW_MyHomeTableView tableView:cellForRowAtIndexPath:] + 1322    4   UIKit                               0x00000001055a2ab2 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 750    5   UIKit                               0x00000001055a2cf8 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74    6   UIKit                               0x0000000105577639 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2845    7   UIKit                               0x00000001055abccc -[UITableView _performWithCachedTraitCollection:] + 111    8   UIKit                               0x0000000105592e7a -[UITableView layoutSubviews] + 233    9   UIKit                               0x00000001054f955b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268    10  QuartzCore                          0x0000000105114904 -[CALayer layoutSublayers] + 146

尋找自己項目的標識,看到frame3位置,你只需這樣查找位置:

image lookup -a 0x00000001009a9f3a      Address: DiDi[0x0000000100609f3a] (DiDi.__TEXT.__text + 6323194)      Summary: DiDi`-[FW_MyHomeTableView tableView:cellForRowAtIndexPath:] + 1322 at FW_MyHomeTableView.m:243

項目中FW_MyHomeTableView.m:243,perfect!

3.2 image lookup -name 查找方法來源

此命令可以用來查找方法的來源。包括在第三方SDK中的方法,也能被查到。
例:查找transformOtherModelToSuit:

(lldb) image lookup -n transformOtherModelToSuit:1 match found in /Users/xxx/Library/Developer/Xcode/DerivedData/DiDi-cwpbvvyvqmeijmcjnneothzuthsy/Build/Products/Debug-iphonesimulator/DiDi.app/DiDi:        Address: DiDi[0x0000000100293d60] (DiDi.__TEXT.__text + 2693664)        Summary: DiDi`+[FW_BetFunction transformOtherModelToSuit:] at FW_BetFunction.m:107

3.3 image lookup –type 查看成員

查看某個class的所有屬性和成員變量。不過貌似frameWork庫中文件不能查看。

(lldb) image lookup -t MatchEvent1 match found in /Users/xxxx/Library/Developer/Xcode/DerivedData/DiDi-cwpbvvyvqmeijmcjnneothzuthsy/Build/Products/Debug-iphonesimulator/DiDi.app/DiDi:id = {0x00433d32}, name = "MatchEvent", byte-size = 48, decl = MatchEvent.h:11, compiler_type = "@interface MatchEvent : NSObject{    BOOL _isHome;    NSString * _playerName;    NSString * _timePoint;    NSString * _eventType;    NSString * _eventDesc;}@property ( getter = isHome,setter = setIsHome:,assign,readwrite,nonatomic ) BOOL isHome;@property ( getter = playerName,setter = setPlayerName:,readwrite,copy,nonatomic ) NSString * playerName;@property ( getter = timePoint,setter = setTimePoint:,readwrite,copy,nonatomic ) NSString * timePoint;@property ( getter = eventType,setter = setEventType:,readwrite,copy,nonatomic ) NSString * eventType;@property ( getter = eventDesc,setter = setEventDesc:,readwrite,copy,nonatomic ) NSString * eventDesc;@end"

4 breakpoint4.1 文件名+行號 breakpoint set -f xxx -l xxx

我們平時操作xcode,在某一行點下斷點,其實操作的就是這個命令。

(lldb) breakpoint set -f FW_ProfilesDetailModel.m -l 95Breakpoint 3: where = DiDi`-[FW_ProfilesDetailModel incomeRate] + 27 at FW_ProfilesDetailModel.m:96, address = 0x0000000105b404bb

4.2 函數名斷點4.2.1 方法名斷點 breakpoint set -n 方法名

(lldb) breakpoint set -n viewDidLoadBreakpoint 4: 414 locations.

Tips:這裡要說一下,xcode其實也有函數名斷點,不過用breakpoint set -n實現,比xcode下斷點快N倍,不過xcode下的斷點還給提示所有斷到的位置。

4.2.2 類中方法斷點 breakpoint set -n 「-[類名 方法名]」

(lldb) breakpoint set -n "-[FW_MyHomeViewController viewDidLoad]"Breakpoint 8: where = DiDi`-[FW_MyHomeViewController viewDidLoad] + 20 at FW_MyHomeViewController.m:58, address = 0x0000000105aec944

注意:-[FW_MyHomeViewController viewDidLoad],外面一定要加雙引

號,不然會誤識別為-[FW_MyHomeViewController`

4.3 條件斷點 breakpoint set -c 「xxxx」

和xcode中symbolic Breakpoint功能相同,我在FW_HomeCell.m 362行下斷點,但又想過濾僅width>68的狀態,操作如下:

breakpoint set -f FW_HomeCell.m -l 362 -c "width > 68"Breakpoint 5: where = DiDi`-[FW_HomeCell_HotBill setDataSource:] + 2006 at FW_HomeCell.m:363, address = 0x000000010d22e0a6

4.4 查看斷點列表 breakpoint list

(lldb) breakpoint listCurrent breakpoints:8: name = '-[FW_MyHomeViewController viewDidLoad]', locations = 1, resolved = 1, hit count = 28.1: where = DiDi`-[FW_MyHomeViewController viewDidLoad] + 20 at FW_MyHomeViewController.m:58, address = 0x0000000105aec944, resolved, hit count = 2 9: file = '/Users/xxxx/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 09.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0

4.5 禁用/啟用斷點 breakpoint disable/enable

//禁用斷點(lldb) breakpoint disable 91 breakpoints disabled.(lldb) breakpoint listCurrent breakpoints:9: file = '/Users/zmz/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1 Options: disabled 9.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, unresolved, hit count = 0//啟用斷點(lldb) breakpoint enable 91 breakpoints enabled.(lldb) breakpoint listCurrent breakpoints:9: file = '/Users/zmz/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 09.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0

4.6 移除斷點 breakpoint delete

(lldb) breakpoint delete 81 breakpoints deleted; 0 breakpoint locations disabled.(lldb) breakpoint listCurrent breakpoints:9: file = '/Users/xxxx/didi-ios/DiDi/FollowWinner/Model/FW_HomeModel.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 09.1: where = DiDi`+[FW_HomeModel_Rank parasWithDict:limitNickLength:] + 89 at FW_HomeModel.m:24, address = 0x00000001061bc169, resolved, hit count = 0

結語:

有了這些命令,調試起來肯定就得心應手了。總結下常用的,供多看幾遍加深回憶:

堆棧相關:bt查看堆棧、frame select跳幀、frame variable查看幀參數、thread return跳出當前執行、【step/finish/next/continue】進入/跳出/下一步/跳出本斷點

斷點相關:breakpoint set -f -l -c條件斷點、breakpoint set -n方法斷點、breakpoint delete斷點移除、breakpoint list斷點列表

image命令:image lookup -address崩潰定位、image lookup -name方法來源、 image lookup –type 查看成員

LLDB支持簡寫

相關焦點

  • LLDB命令庫HMLLDB介紹
    /Users/pal/Desktop/gitProjects/HMLLDB/commands/HMLLDB.py重啟Xcode,運行你自己的iOS項目,點擊Pause program execution進入LLDB調試模式,輸入命令help,如果看到有下文介紹的命令,表明安裝成功。
  • iOS逆向常用命令:dpkg、LLDB、python-client、debugserver、socat、SSH、cycript
    前言整理iOS逆向開發中常用到的命令I 、dpkg
  • 如何更好地利用 iOS Crash Log
    除了蘋果的服務外,還有一些第三方提供了這些服務,國外的有 Crashlytics,國內常用的有友盟、騰訊的 bugly 等。除了 lldb 外,我們還需要準備好的是當時提交 App Store 的 archive 文件,在 Xcode 的 Organizer 裡的 Archives 面板裡能找到導出功能。然後我們需要做的是打開 Terminal,輸入 lldb。沒看錯,我們天天接觸的 lldb 其實是個可以脫離 Xcode 獨立使用的命令行工具。
  • ADB常用命令
    ,如安裝和調試應用,並提供對 Unix shell(可用來在模擬器或連接的設備上運行各種命令)的訪問。您可以通過發出 adb 命令從命令行終端調用客戶端。後臺程序:該組件在設備上運行命令。後臺程序在每個模擬器或設備實例上作為後臺進程運行。伺服器:該組件管理客戶端和後臺程序之間的通信。伺服器在開發計算機上作為後臺進程運行。
  • 【linux】常用命令之scp命令
    linux命令之scp命令用於linux之間文件或者目錄的複製。scp的全稱為secure copy,是基於ssh登錄進行安全的遠程文件或目錄copy命令,當然只能用於linux系統之間。命令格式:scp [-optional] source_file target_file其中optional可寫也可不寫,參數為:-1: 強制scp命令使用協議ssh1-2: 強制scp命令使用協議ssh2-4: 強制
  • Unity3D遊戲修改&iOS免越獄hook
    Mac-mini:frida-ios-dump-master-2 $ frida-ps -U PID Name---- ----2911 App Store2947 信息2980 密室逃脫絕境系列11遊樂園2936 微信2972 設置2949 郵件2814 AppleIDAuthAgent1412  AssetCacheLocatorService
  • 一天一個 Linux 命令:objdump 命令
    1.功能簡介objdump 命令是 GNU Binutils 二進位工具集的一員,用於查看目標文件或可執行文件的組成信息,以可讀的形式列印二進位文件的內容。企圖解析保存在文件中的調試信息並以 C 語言的語法顯示出來。僅僅支持某些類型的調試信息。
  • 每天一個 Linux 命令(106):objdump 命令
    1.功能簡介objdump 命令是 GNU Binutils 二進位工具集的一員,用於查看目標文件或可執行文件的組成信息,以可讀的形式列印二進位文件的內容。企圖解析保存在文件中的調試信息並以 C 語言的語法顯示出來。僅僅支持某些類型的調試信息。
  • adb的一些常用命令
    本文簡單介紹一些常用的adb命令。
  • iOS-Swift 結構體與類
    以上就是 Swift 的編譯流程,下面為編譯流程的命令。: UInt16var reserved: UInt16var classSize: UInt32var classAddressPoint: UInt32var typeDescriptor: UnsafeMutableRawPointervar iVarDestroyer: UnsafeRawPointer}(滑動顯示更多) 接下來我們做一個測試,通過 lldb
  • 10分鐘學會Bash調試
    ,本文主要介紹shell腳本常用的調試方法調試常用選項調試shell腳本時,常常用到幾個調試選項,讓腳本在執行的過程中,會輸出一些調試信息,根據調試信息,就可以定位出具體出問題的代碼具體的選項以及說明如下:選項說明-x輸出結果之前,先輸出執行的命令-u遇到不存在的變量就會報錯
  • 讓代碼調試不再難 - pdb
    進入調試模式進入調試模式,方法很簡單,就像正常執行python腳本一樣,只是多加了-m pdb:python -m pdb pdb_demo.py使用這個方式進入調試模式,會在腳本的第一行開始單步調試。
  • 四種繞過iOS SSL驗證和證書固定的方法
    只需運行以下簡單命令即可,其中-s是IPA文件,-c是代碼籤名證書。一旦命令執行完畢,就會為我們生成一個名為netspi_test-frida-codesigned.ipa的新IPA文件,我們可以將其部署到iOS設備上。有一個名為ios-deploy的工具,可以和未越獄的iOS設備配合使用。我們可以使用多種不同的選項,具體取決於你要完成的任務(例如,運行調試器,通過USB部署應用程式等)。
  • JVM 常用命令行工具
    優質文章,第一時間送達  作者 |  低吟不作語來源 |  urlify.cn/Rz67bm76套java從入門到精通實戰課程分享一、基礎故障處理工具Java 開發人員肯定都知道 JDK 的 bin 目錄下有許多小工具,這些小工具除了用於編譯和運行 Java 程序外,打包、部署、籤名、調試
  • Python使用pdb更優雅的調試代碼
    如果沒有IDE或者命令行寫代碼時又該怎樣快速調試?這時如果使用pdb進行調試將會異常方便。Pdb就是Python debugger ,是python自帶的調試器。通過 pdb 我們可以交互式的查看運行過程中變量的值、設置斷點、逐行執行代碼、查看代碼的調用棧等等。並且如果環境沒有 GUI 的話,那麼 pdb 能夠助你更快速的調試代碼。
  • 常用網絡命令
    16.debug[debug-value]設置調試方式,顯示發送至遠程主機的每條命令,如debup3,若 設為0,表示取消debug。17.dir[remote-dir][local-file]顯示遠程主機目錄,並將結果存入local-file。18.disconnection同close。
  • GDB 調試實戰之 Redis 通信協議
    ); } } } /* Free the argument vector */ sdsfreesplitres(argv,argc); } /* linenoise() returns
  • linux應急常用命令+技巧總結
    不輸的辦法只有一個,就是不上場常用命令top # 命令可以直接看到進程實時情況。