LLDB 知多少

重識 LLDB

LLDB 是什麼?

 「若是調試是刪除 bug 的過程,那麼編程就是引入 bug 的過程。」(Edsger W. Dijkstra)html

 對於蘋果開發者而言,LLDB 是無人不知的調試工具,然而此知非彼知,相信有至關規模的開發者對 LLDB 的瞭解仍然停留於幾個基礎命令的使用,今天讓咱們來從新認識一下既熟悉又陌生的 LLDB,看看它那些你未曾用過的強大功能,以及如何提升咱們的開發效率。git

 開始把玩其功能以前,先搞清楚 LLDB 是什麼,簡言之,LLDB 是一個有着 REPL 的特性和 C++ 、Python 插件的開源調試器。github

 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 Mac OS X and supports debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.express

 以上摘自官方文檔中的一段簡短的介紹,更多相關信息請參閱 LLDB 官方文檔編程

LLDB 命令結構

 知道了 LLDB 是什麼,還要了解其命令結構及語法,這樣才能告別死記命令,開啓壓榨 LLDB 之路了。LLDB 通用結構的形式以下:sass

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]markdown

其中:函數

  • command、subcommand:LLDB調試命令的名稱。命令和子命令按層級結構來排列:一個命令對象爲跟隨其的子命令對象建立一個上下文,子命令又爲其子命令建立一個上下文,依此類推。
  • action:命令操做,想在前面的命令序列的上下文中執行的一些操做。
  • options:命令選項,行爲修改器(action modifiers)。一般帶有一些值。
  • argument:命令參數,根據使用的命令的上下文來表示各類不一樣的東西。
  • []:表示命令是可選的,能夠有也能夠沒有。

舉個例子:工具

命令:breakpoint set -n main 對應到上面的語法就是:oop

  • command:breakpoint 斷點命令
  • action:set 設置斷點
  • option:-n 表根據方法 name 設置斷點
  • arguement:mian 表示方法名爲 mian

關於原始命令

 LLDB支持不帶命令選項的原始命令,原始命令會將命令後面的全部東西當作參數(arguement)處理。但不少原始命令也能夠帶命令選項,當你使用命令選項的時候,須要在命令選項後面加 -- 區分命令選項和參數。
 如:expression (就是 p/print/call)、expression -o(就是 po),打印一個UIView對象地址:

 前者是計算其地址的值,後者調用了對象的 description 方法,其中體現了惟一匹配原則:假如根據前n個字母已經能惟一匹配到某個命令,則只寫前n個字母等效於寫下完整的命令。再用設置斷點的命令舉例,下面兩條命令等效:
 更多命令結構的介紹及用法,請參考 LLDB 入門。接下來介紹點 LLDB 最實用又最容易被忽略的用法。


LLDB 經常使用命令總結

輔助記憶:apropos

 當咱們並不能徹底記得某個命令的時候,使用 apropos 經過命令中的某個關鍵字就能夠找到全部相關的命令信息。 好比: 咱們想使用stop-hook的命令,可是已經不記得stop-hook命令是啥樣了:

實在記不起來也不要慌,這裏有 LLDB command map

一.斷點設置

 關於斷點設置,多數人都習慣用圖形界面去作,但在調試中有些場景僅僅靠圖形界面仍是不夠的,好比:如何經過斷點實現相似 KVO 那樣對成員變量變化的監聽呢?(別跟我說你要加代碼重寫set方法...即便這樣也不靠譜)。下面一一羅列那些好用的斷點命令:

  1. breakpoint list:查看全部斷點列表
  2. breakpoint delete:刪除全部斷點(可跟組號刪除指定組)
  3. breakpoint disable/enable:禁用 啓用指定斷點
  4. breakpoint set -r some:遍歷整個項目中包含 some 這個字符的全部方法並設置斷點
  5. breakpoint 支持按文件名、函數名、行數、正則等各類條件篩選設置斷點,請結合語法並參考官方文檔
  6. watchpoint set expression 0x10cc64d50:在內存中爲地址爲0x10cc64d50的對象設置內存斷點
  7. watchpoint set variable xxoo:爲當前對象的變量 xxoo 設置內存斷點
  8. target stop-hook add -o "frame variable":添加每次程序 stop 時都但願執行的命令:frame variable(打印當前棧內的全部變量)
  9. target stop-hook、watchpoint 的增刪改查命令與 breakpoint 的基本相同
  10. 更多變態斷點玩法需自定義插件支持,火燒眉毛的你請直接轉至文末。

二.流程控制

這兩幅圖你必定不陌生:

  1. 圖一
  2. 圖二
  • 第一個按鈕:continue/c 繼續執行
  • 第二個按鈕:
    • 圖一: thread step-over/next/n 當前線程下一步(以一個完整子函數爲一步)
    • 圖二: thread step-inst-over/ni 當前線程下一步(以一個彙編函數爲一步)
  • 第三個按鈕:
    • 圖一: thread step-in/step/s 當前線程下一步(遇到子函數就進入而且繼續單步執行)
    • 圖二: thread step-inst-over/si 當前線程下一步(遇到彙編函數就進入而且繼續單步執行彙編指令)
  • 第四個按鈕:thread step-out/finish 退出當前幀棧

其餘命令:

  • thread return:它有一個可選參數,在執行時它會把可選參數加載進返回寄存器裏,而後馬上執行返回命令,跳出當前棧幀。這意味這函數剩餘的部分不會被執行。這會給 ARC 的引用計數形成一些問題,或者會使函數內的清理部分失效。可是在函數的開頭執行這個命令,是個很是好的隔離目標函數、僞造返回值的方式。

三.可執行文件&共享庫查詢命令

這些命令在逆向及定位錯誤時使用頻率很是高。

  1. image list:列出主要的可執行文件和全部依賴的共享庫。
  2. image lookup --address 0x1ec4:在可執行文件或任何共享庫中查找原始地址信息。
  3. image lookup -v --address 0x1ec4:查找完整的源代碼行信息。
  4. image lookup --type NSString:根據名稱查找對應(NSString)類型的信息。

四.其餘經常使用命令模板

  1. register read:顯示當前線程的通用寄存器。
  2. register write rax 123:將一個新的十進制值「123」寫入當前線程寄存器「rax」。
  3. memory read --size 4 --format x --count 4 0xbffff3c0:從地址0xbffff3c0讀取內存,並顯示4個十六進制uint32_t值。

增強版 LLDB —— 修改 .lldbinit 文件 & 插件安裝

 前面所列的命令在 這裏 都能找到官方說明,更多命令用法有興趣的建議本身去細細探索,接下來咱們將站在巨人的肩膀上,用高手們專門爲 LLDB 寫的插件去深刻挖掘它的潛力。

  1. 推薦插件一: facebook 開源的 LLDB 插件 chisel

    brew install chisel 的安裝過程這裏就不贅述了,安裝成功後,在~/目錄下的 .lldbinit 文件中引入對應文件路徑,增長一行:command script import /usr/local/opt/chisel/libexec/fblldb.py 後保存, 重啓 Xcode便可使用。它提供的快捷 命令清單及說明 這裏也不贅述了。截個圖感覺下它的強大吧:

  2. 推薦插件二DerekSelander/LLDB

    該插件與 chisel 都是用 Python 寫的,其安裝須要手動下載倉庫,而後將倉庫中 dslldb.py 文件的路徑用與上述一樣的方式添加到 .lldbinit 中,具體用法也很簡單粗暴,就不在這粘貼了,請至 README 領略。

總結:

 看到這,你收穫的只有暫時記憶,其實等於毫無所獲...並且還浪費了寶貴的幾分鐘,這不是你但願的結果,而避免其成爲事實的惟一方式就是:實踐。打開 Xcode,運行一個項目,參照着文中涉及到的說明文檔,試着敲一敲每一個命令,體會一下它們的用法與區別。最後,爲你的 LLDB 配好插件,去感覺它的蛻變,相信我,你的開發效率提高的可不止一點點。學習是一種能力,拒絕操做手冊式灌輸,分享者多半是在總結學習收穫時爲讀者提供一些思路或方向,這也是我爲你保留一絲探索餘地的初衷,願你有所收穫。

 水平有限,請大神多多指正。下篇再會~

相關文章
相關標籤/搜索