iOS 常用調(diào)試方法:LLDB命令

級別: ★☆☆☆☆
標簽:「Xcode控制臺調(diào)試」「iOS 調(diào)試臺」「iOS Console」
作者: Xs·H
審校: QiShare團隊


在iOS項目開發(fā)過程中引颈,常用到靜態(tài)分析(Analyze)怠惶、斷點(Breakpoint)和控制臺(Console)進行代碼調(diào)試,其中控制臺調(diào)試最核心的的就是LLDB命令氓栈。本篇文章介紹作者在項目中最常用到的LLDB命令調(diào)試方法供填。

一拐云、簡介

LLDB是新一代高性能調(diào)試器。 它構(gòu)建為一組可重用的組件近她,可以高度利用較大的LLVM項目中的現(xiàn)有庫叉瘩,例如Clang表達式解析器和LLVM反匯編程序。
LLDB是Mac OS X上Xcode的默認調(diào)試器泄私,支持在桌面和iOS設備和模擬器上調(diào)試C房揭,Objective-C和C ++备闲。
LLDB項目中的所有代碼都是在標準LLVM許可證下提供的,這是一種開源的“BSD風格”許可證捅暴。
更多介紹可從LLDB Homepage獲取恬砂。

二、幫助

LLDB命令格式如下:
<命令名稱> <命令動作> [-可選項 [可選項的值]] [參數(shù)1 [參數(shù)2...]]

LLDB命令的各部分由空格分割蓬痒,如果參數(shù)中包含空格泻骤,則需要使用雙引號括起參數(shù),如果參數(shù)中包含雙引號或者反斜杠梧奢,則需要使用反斜杠進行轉(zhuǎn)義狱掂。

LLDB命令有非常多的功能,完全背下來不太容易亲轨,也沒必要趋惨。開發(fā)者可以使用help命令查看相關(guān)命令的用法,甚至可以查看help命令的用法惦蚊。

(lldb) help help
     Show a list of all debugger commands, or give details about a specific
     command.

Syntax: help [<cmd-name>]

Command Options Usage:
  help [-ahu] [<cmd-name> [<cmd-name> [...]]]

       -a ( --hide-aliases )
            Hide aliases in the command list.

       -h ( --show-hidden-commands )
            Include commands prefixed with an underscore.

       -u ( --hide-user-commands )
            Hide user-defined commands from the list.
     
     This command takes options and free-form arguments.  If your arguments
     resemble option specifiers (i.e., they start with a - or --), you must use
     ' -- ' between the end of the command options and the beginning of the
     arguments.

三器虾、執(zhí)行

在LLDB中,執(zhí)行命令expression是最基礎的命令蹦锋,簡寫為expr或者e兆沙,語法為:expression <cmd-options> -- <expr>,它的作用是執(zhí)行一個表達式莉掂,并輸出表達式返回的結(jié)果葛圃。示例如下。

//! 輸出count的值
(lldb) expression count
(NSUInteger) $0 = 10

//! 執(zhí)行string的拼接字符串方法
(lldb) expression [string stringByAppendingString:@"732"]
(__NSCFString *) $1 = 0x00006000006ac870 @"QiShare732"

//! 修改view的顏色
(lldb) expression self.view.backgroundColor = [UIColor redColor]
(UICachedDeviceRGBColor *) $2 = 0x0000600001d74780
(lldb) expression [CATransaction flush]
//!< 因為斷點會終止UI線程憎妙,執(zhí)行[CATransaction flush]命令可以渲染出修改后的界面

四库正、打印

打印命令print是最常用的命令,簡寫為pri或者p尚氛,語法為:print <expr>诀诊,它的作用是打印變量或者表達式。通過help print會發(fā)現(xiàn)print其實是expression --命令的簡寫:'print' is an abbreviation for 'expression --'阅嘶,其中--標識選項的結(jié)束和參數(shù)的開始属瓣。
同樣常用的expression簡寫命令還有pocall。其中po表示print object讯柔,用來打印對象抡蛙,call用來調(diào)用某個方法。示例如下:

(lldb) expression -- self.view
(UIView *) $4 = 0x00007f8ca8401690

(lldb) e self.view
(UIView *) $5 = 0x00007f8ca8401690

(lldb) p self.view
(UIView *) $6 = 0x00007f8ca8401690

(lldb) po self.view
<UIView: 0x7f8ca8401690; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x6000008a1dc0>>

(lldb) call self.view
(UIView *) $8 = 0x00007f8ca8401690

另外魂迄,開發(fā)者可以按照print/<fmt>的語法為print命令指定打印格式:

p/x  //!< 以十六進制打印整數(shù)
p/d  //!< 以帶符號的十進制打印整數(shù)
p/u  //!< 以無符號的十進制打印整數(shù)
p/o  //!< 以八進制打印整數(shù)
p/t  //!< 以二進制打印整數(shù)
p/a  //!< 以十六進制打印地址
p/c  //!< 打印字符常量
p/f  //!< 打印浮點數(shù)
p/s  //!< 打印字符串
p/r  //!< 格式化打印

示例如下:

(lldb) p count
(NSUInteger) $0 = 10

(lldb) p/t count
(NSUInteger) $1 = 0b0000000000000000000000000000000000000000000000000000000000001010

(lldb) p/o count
(NSUInteger) $2 = 012

(lldb) p/x count
(NSUInteger) $3 = 0x000000000000000a

(lldb) p/x string
(__NSCFConstantString *) $4 = 0x000000010416a0b8 @"QiShare"

(lldb) p/c string
(__NSCFConstantString *) $5 = \xb8\xa0\x16\x04\x01\0\0\0 @"QiShare"

(lldb) p/s string
(__NSCFConstantString *) $6 = @"QiShare"

(lldb) p/a string
(__NSCFConstantString *) $7 = 0x000000010416a0b8 @"QiShare" @"QiShare"

五粗截、線程

thread是線程相關(guān)的命令,語法為thread <subcommand> [<subcommand-options>]捣炬,它可以接受不同的可選參數(shù)熊昌,以實現(xiàn)豐富的功能绽榛。其中thread listthread backtracethread return較為常用婿屹。
開發(fā)者可以使用thread list命令查看當前的所有線程灭美,示例如下:

(lldb) thread list
Process 4031 stopped
* thread #1: tid = 0x25cac, 0x0000000104167e23 QiDebugDemo`-[QiConsoleViewController testLLDBCommands](self=0x00007f850df0bbf0, _cmd="testLLDBCommands") at QiConsoleViewController.m:34, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
  thread #2: tid = 0x25d2f, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #3: tid = 0x25d30, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #4: tid = 0x25d31, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #5: tid = 0x25d32, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #6: tid = 0x25d33, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #7: tid = 0x25d3e, 0x00000001079f520a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'

thread backtrace命令可以方便地供開發(fā)者查看線程堆棧信息,簡寫為bt昂利。比如届腐,當程序崩潰的時候,開發(fā)者可以查看堆棧調(diào)用列表蜂奸。示例如下犁苏。

(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x0000000104cc2705 libobjc.A.dylib`objc_exception_throw
    frame #1: 0x00000001056704ec CoreFoundation`_CFThrowFormattedException + 194
    frame #2: 0x00000001057a6b00 CoreFoundation`-[__NSArrayI objectAtIndexedSubscript:] + 96
  * frame #3: 0x00000001043a1df7 QiDebugDemo`-[QiConsoleViewController testLLDBCommands](self=0x00007fadc7c50400, _cmd="testLLDBCommands") at QiConsoleViewController.m:33
    frame #4: 0x00000001043a1d5a QiDebugDemo`-[QiConsoleViewController viewDidLoad](self=0x00007fadc7c50400, _cmd="viewDidLoad") at QiConsoleViewController.m:26
...
    frame #18: 0x00000001056830be CoreFoundation`__CFRunLoopDoObservers + 430
    frame #19: 0x0000000105683751 CoreFoundation`__CFRunLoopRun + 1537
    frame #20: 0x0000000105682e11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #21: 0x000000010ddd51dd GraphicsServices`GSEventRunModal + 62
    frame #22: 0x000000010a1db81d UIKitCore`UIApplicationMain + 140
    frame #23: 0x00000001043a2450 QiDebugDemo`main(argc=1, argv=0x00007ffeeb85df90) at main.m:7
    frame #24: 0x0000000107858575 libdyld.dylib`start + 1

在調(diào)試過程中,開發(fā)者可以使用thread return命令終端某個方法并返回一個想要的值扩所。示例如下围详。

(lldb) thread return string
(lldb) continue
2019-02-27 17:22:47.323225+0800 QiDebugDemo[5071:222700] resultString: Qi_Share

六、斷點

作者在iOS 調(diào)試方法:斷點這篇文章中介紹過斷點的用法碌奉。其實短曾,可視化的斷點都可以使用LLDB語法來實現(xiàn)。比如下圖中的1赐劣、2、3哩都、4魁兼、5都能用LLDB命令表達。

  1. 啟用/禁用斷點(breakpoint enable/disable)
  2. 繼續(xù)執(zhí)行程序(continue)
  3. 執(zhí)行下一步(next)
  4. 進入方法(step)
  5. 跳出方法(finish)

在斷點相關(guān)操作中漠嵌,因為Xcode已經(jīng)集成了可視化的斷點操作工具咐汞,所以breakpoint命令并不被常用。但是儒鹿,breakpoint命令擁有著十分強大的功能化撕,語法為:breakpoint <subcommand> [<command-options>],主要命令示例如下约炎。

//! 查看所有斷點
(lldb) breakpoint list

//! 為所有類中的viewDidAppear:設置斷點
(lldb) breakpoint set -n viewDidAppear:

//! 為QiConsoleViewController.m文件中的testLLDBCommands方法設定斷點
(lldb) breakpoint set -f QiConsoleViewController.m -n testLLDBCommands

//! 為QiConsoleViewController.m文件中的第32行代碼設定斷點
(lldb) breakpoint set -f QiConsoleViewController.m -l 32

//! 為handleString:方法設定條件斷點植阴,條件為string != nil
(lldb) breakpoint set - handleString: -c string != nil

七、觀察點

想比較于breakpoint是對方法生效的斷點圾浅,watchpoint則是對地址生效的斷點掠手。watchpoint類似于KVO的工作原理,當觀察到屬性地址里面的東西改變時狸捕,就讓程序中斷喷鸽,其語法為:watchpoint <subcommand> [<command-options>]。其應用場景示例如下灸拍。

(lldb) watchpoint set variable string
Watchpoint created: Watchpoint 1: addr = 0x7ffeef497360 size = 8 state = enabled type = w
    declare @ '/Users/huangxianshuai/Desktop/Products/QiShare/QiDebugDemo/QiDebugDemo/QiConsoleViewController.m:33'
    watchpoint spec = 'string'
    new value: 0x00000001007670b8

(lldb) next

Watchpoint 1 hit:
old value: 0x00000001007670b8
new value: 0x0000000100767138

(lldb) image lookup -a 0x00000001007670b8
      Address: QiDebugDemo[0x00000001000040b8] (QiDebugDemo.__DATA.__cfstring + 32)
      Summary: @"QiShare"
(lldb) image lookup -a 0x0000000100767138
      Address: QiDebugDemo[0x0000000100004138] (QiDebugDemo.__DATA.__cfstring + 160)
      Summary: @"huang"

image lookup -aimage lookup -address的簡寫做祝,可以查看參數(shù)地址的內(nèi)容砾省。

總結(jié)

文章僅列舉了作者平常使用到的一些LLDB命令,這些命令的確能提高調(diào)試效率混槐。而更多的LLDB命令可以從LLDB Homepage或者其他網(wǎng)絡資源中獲取编兄。


推薦文章:
iOS消息轉(zhuǎn)發(fā)
iOS 自定義拖拽式控件:QiDragView
iOS 自定義卡片式控件:QiCardView
iOS Wireshark抓包
iOS Charles抓包

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纵隔,隨后出現(xiàn)的幾起案子翻诉,更是在濱河造成了極大的恐慌,老刑警劉巖捌刮,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碰煌,死亡現(xiàn)場離奇詭異,居然都是意外死亡绅作,警方通過查閱死者的電腦和手機芦圾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俄认,“玉大人个少,你說我怎么就攤上這事∶行樱” “怎么了夜焦?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岂贩。 經(jīng)常有香客問我茫经,道長,這世上最難降的妖魔是什么萎津? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任卸伞,我火速辦了婚禮,結(jié)果婚禮上锉屈,老公的妹妹穿的比我還像新娘荤傲。我一直安慰自己,他們只是感情好颈渊,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布遂黍。 她就那樣靜靜地躺著,像睡著了一般儡炼。 火紅的嫁衣襯著肌膚如雪妓湘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天乌询,我揣著相機與錄音榜贴,去河邊找鬼。 笑死,一個胖子當著我的面吹牛唬党,可吹牛的內(nèi)容都是我干的鹃共。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驶拱,長吁一口氣:“原來是場噩夢啊……” “哼霜浴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蓝纲,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤阴孟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后税迷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體永丝,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年箭养,在試婚紗的時候發(fā)現(xiàn)自己被綠了慕嚷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毕泌,死狀恐怖喝检,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撼泛,我是刑警寧澤挠说,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站愿题,受9級特大地震影響纺涤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抠忘,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望外永。 院中可真熱鬧崎脉,春花似錦、人聲如沸伯顶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祭衩。三九已至灶体,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掐暮,已是汗流浹背蝎抽。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留路克,地道東北人樟结。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓养交,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓢宦。 傳聞我的和親對象是個殘疾皇子碎连,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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