LLDB(Low-Level Debugger)はLLVMプロジェクトの次世代デバッガであり、iOS、macOS、tvOS、watchOS向けアプリケーションのデバッグのためにXcodeに含まれています。GDBとは異なり、LLDBはLLVMコンパイラを使用したモジュラーアーキテクチャを採用しており、高速かつ高精度なデバッグを実現します。LLVMプロジェクトによると、LLDBはC、Objective-C、C++、Swiftでのデバッグをサポートし、ブレークポイント、ウォッチポイント、メモリ検査、ステップ実行などの完全な機能セットを備えています。
重要ポイント
LLDBはLLVMプロジェクトのライブラリ上に構築されたオープンソースのデバッガです。Xcode 5でGDBを置き換え、それ以来Appleエコシステム全体の主要なデバッグツールとなっています。モノリシックなGDBとは異なり、LLDBは相互に作用するライブラリのセットとして実装されています。式の解析からメモリ管理まで、各機能は個別のモジュールに配置され、保守と拡張が容易になっています。
LLDBの主な機能には、あらゆるタイプのブレークポイントの設定、変数の変更を追跡するウォッチポイント、メモリとレジスタの検査、ステップ実行、停止したプログラムのコンテキストでの任意の式の評価、自動化のためのPythonスクリプトの実行が含まれます。LLVMリポジトリによると、LLDBは200以上のデバッグコマンドをサポートし、Appleエコシステムの主要なデバッグ情報形式であるDWARFおよびMach-O形式と互換性があります。
LLDBの重要な利点は、Clangとの深い統合です。ソースコードの解析とコンパイルに同じコンパイラを使用することで、LLDBはGDBでは不可能な精度でC++およびObjective-Cの式を評価できます。Swiftデバッグの場合、LLDBは言語のセマンティクス(オプショナル型、プロトコル、ジェネリクス、ARCによるメモリ管理)を理解する個別のSwift Language Runtimeモジュールを使用します。
LLDBの最初のバージョンは2010年にLLVM 2.8の一部として登場しました。2013年までにXcodeのGDBを完全に置き換えました。2019年、Xcode 11のリリースに伴い、LLDBはSwift Error BreakpointsのサポートとSwift用の改良された式パーサーを獲得しました。Appleによると、iOS 14以降、シミュレータのデバッグスタック全体もLLDBを介して動作し、プラットフォームの主要なデバッグツールとしての地位を確立しています。
LLDBアーキテクチャはマイクロサービス原則に基づいて構築されています。各サブシステムは個別のライブラリ(dylib)として存在し、共通のAPIを介して相互に接続されます。これは、すべての機能が単一のバイナリに結合されているGDBとは異なります。モジュラー構造により、LLDBコンポーネントを独立して使用できます。たとえば、式パーサーは完全なデバッガを接続せずにIDEに組み込むことができます。
| LLDBコンポーネント | 目的 | ライブラリ |
|---|---|---|
| Core | デバッグプロセス管理、イベント、スレッド状態 | liblldbCore.dylib |
| Expression Parser | 式の解析と実行(C/C++/ObjC/Swift) | liblldbExpression.dylib |
| Symbol File | DWARF、Mach-O、dSYMの読み取り — デバッグ情報の処理 | liblldbSymbol.dylib |
| Target Control | 実行制御:起動、停止、ステップ | liblldbTarget.dylib |
| Interpreter | コマンドラインとREPLモード | liblldbInterpreter.dylib |
dSYMは、Xcodeがビルド時に生成するデバッグ情報ファイルです。LLDBはこれらを使用してマシンコードをソースコードにマッピングします。dSYMがない場合、デバッガは関数名やコード行の代わりにメモリアドレスのみを表示します。App Storeアプリケーションの場合、dSYMファイルはAppleサーバーに個別にアップロードされ、CrashReporterを介してユーザーから受信したクラッシュログのシンボル化に使用されます。
(lldb) target create MyApp.app
(lldb) image list MyApp
MyApp - "/path/to/MyApp.app/MyApp" (arm64)
(lldb) image lookup -n fetchUserData
Address: MyApp[0x1000a3b40] (MyApp.__TEXT.__text + 12352)
Summary: `ViewController.fetchUserData()` at ViewController.swift:42
LLDBコマンドは、実行制御、ブレークポイント管理、データ検査、メモリ操作のいくつかのカテゴリに分類されます。XcodeのGUIとは異なり、LLDBコンソールはデバッグを完全に制御し、グラフィカルインターフェースでは利用できない操作(たとえば、変数の値をその場で変更したり、ブレークポイントを一括編集したり)を実行できます。
Continue、Step Over、Step Into、Step Outはデバッグサイクルの基本です。continueは次のブレークポイントまで実行を再開します。step overは現在の行全体を実行します。step intoは呼び出されたメソッドの中に入ります。step outは現在の関数を完了し、呼び出し元のコードに制御を戻します。さらに、step with type filter(指定されたデータ型までのステップ)もあります。
(lldb) thread backtrace # コールスタックを表示
* thread #1, queue = 'com.apple.main-thread'
frame #0: 0x1000a3b40 ViewController`fetchUserData()
frame #1: 0x1000a2000 ViewController`viewDidLoad()
frame #2: 0x1a2b345 UIKit`UIViewController.loadView()
(lldb) frame variable # ローカル変数を表示
(Int) userId = 42
(String) endpoint = "https://api.example.com/user/42"
(lldb) thread step-over # Step Over
(lldb) thread step-in # Step Into
LLDBは任意の形式でデータを表示するコマンドを提供します:memory read、frame variable、target variable。特別な構文po(print object)は、Objective-CオブジェクトのdebugDescriptionとSwift型のdescriptionを呼び出します。カスタムフォーマッタはtype summary addで設定します。CGRectやIndexPathなどの複雑な構造体のデバッグに便利です。
(lldb) po userProfile # オブジェクトの説明を表示
<UserProfile: 0x600000c4b80>
- name: "John"
- age: 30
- email: "john@example.com"
(lldb) expression userProfile.age = 31 # 値を変更
(Int) $R0 = 31
(lldb) memory read 0x600000c4b80 0x600000c4bc0
0x600000c4b80: 6a 6f 68 6e 00 00 00 00 1e 00 00 00 00 00 00 00
式の評価はLLDBの最も強力な機能の1つであり、GDBが主流だった時代には存在しませんでした。LLDBは、停止したプログラムのコンテキストでC、Objective-C、C++、Swiftの任意のコードを実行でき、メソッドの呼び出し、オブジェクトの作成、状態の変更が可能です。これにより、アプリケーションを再起動して再コンパイルすることなく仮説をテストできます。
expressionコマンドは、デバッグ中のプロセスのランタイムで式をコンパイルして実行します。-Oフラグ(object description)はpoをトリガーします。複数行の式にはexpression -l Swift --を使用します。LLDBはClangまたはSwiftコンパイラを介してその場でコードをコンパイルし、結果を現在のコンテキストに統合して値を返します。Appleによると、式は複雑さに応じて10〜50ミリ秒でコンパイルされます。
(lldb) expr -l Swift -- UIAlertController(title: "Test", message: nil,
preferredStyle: .alert)
(lldb) expr let $arr = [1, 2, 3].map { $0 * 2 }
(lldb) po $arr
▿ 3 elements
- 0 : 2
- 1 : 4
- 2 : 6
LLDBはデバッグ中にオブジェクトや変数の状態を読み取るだけでなく変更することもできます。これはエッジケースのテストに重要です。変数をnilに設定したり、UI要素の色を変更したり、サーバーの応答をデバッガ内で直接置き換えたりすることができ、再コンパイルや再起動は不要です。この手法は、再起動に時間がかかるゲーム開発や長いフローを持つアプリケーションで広く使用されています。
(lldb) expr self.label.text = @"Updated"
(lldb) expr -l Swift -- (self as! UIViewController).view.backgroundColor = .red
(lldb) expr let $snapshot = self.view.debugQuickLookObject()
LLDBのPython APIを使用すると、デバッグ自動化のためのスクリプトを作成できます。Pythonを介して、カスタムコマンドの作成、ブレークポイントイベントの処理、レポートの生成、デバッガの動作のオーバーライドまで可能です。組み込みのPython 3インタプリタは、lldbモジュールを介して完全なデバッグAPIにアクセスしながら、LLDB内で直接実行されます。
新しいLLDBコマンドは、Pythonスクリプトの@classmethodデコレータを介して登録できます。スクリプトをインポートすると、コマンドは組み込みとして使用可能になります。たとえば、printvarsコマンドは、現在のフレームのすべての変数をその型と値とともに、特定のプロジェクト用にフォーマットして出力できます。Stack OverflowでのiOS開発者の調査によると、自動化により一般的なデバッグ操作の時間が60〜80%短縮されます。
import lldb
class PrintVarsCommand:
@classmethod
def register_class(cls, debugger, _):
handler = PrintVarsCommand()
debugger.HandleCommand('command script add -c \
print_vars.PrintVarsCommand printvars')
def __call__(self, debugger, command, exe_ctx, result):
frame = exe_ctx.frame
for var in frame.variables:
result.AppendMessage(f"{var.name}: {var.type} = {var.value}")
Python APIを介して、スクリプトをブレークポイントの発火にバインドできます。ブレークポイントを設定し、breakpoint command addを実行してPython関数を指定します。これにより、手動介入なしで自動的に状態をログに記録したり、データを分析に送信したり、不変条件をチェックしたりできます。LLVMによると、このアプローチはAppleのインフラストラクチャで開発中のパフォーマンスメトリクス収集に使用されています。
(lldb) breakpoint set -f Model.swift -l 100
(lldb) breakpoint command add 1 -s python -o "frame = exe_ctx.frame;
print([var.name for var in frame.variables])"
REPL(Read-Eval-Print Loop)はLLDBの対話型モードで、lldb --replコマンドまたはXcodeデバッグコンソールから起動します。REPLでは、プレイグラウンドのようにSwiftやCコードを実行でき、即座にフィードバックが得られます。LLDBは各行をコンパイル、実行し、結果を表示します。APIの実験、アルゴリズムのプロトタイプ作成、プロジェクトを作成せずに言語の新機能を学ぶのに便利です。
(lldb) --repl
1> let numbers = [1, 2, 3, 4, 5]
2> numbers.filter { $0 % 2 == 0 }
$R0: [Int] = 2 values {
[0] = 2
[1] = 4
}
3> let result = numbers.reduce(0, +)
$R1: Int = 15
REPLモードはimportを介したモジュールとフレームワークのロードもサポートしています。たとえば、REPLでimport UIKitとするとUIKitライブラリ全体がロードされ、UI要素の作成、制約の確認、アニメーションのテストが可能です。これはGDBでは利用できない、iOS開発者にとってユニークな機能です。同じ環境でのデバッグとプロトタイピングを実現します。
Swiftコンパイラとの統合により、LLDB REPLはAppleのコースでSwiftを教えるために使用されています。学生はプロジェクトのセットアップに煩わされることなく、コードを1行ずつ実行し、型や結果を確認できます。このアプローチはアクティブラーニングの方法論に従っており、インタラクティブなフィードバックがコンピュータサイエンス教育の研究によると教材の理解を40%加速します。
よくある質問
LLDBはモジュラーなLLVMアーキテクチャ上に構築されており、式の評価速度と最新言語(Swift)のサポートで優れています。GDBはモノリシックなデバッガで、Swiftをサポートしておらず、スクリプティング機能も限られています。
xcode-select --installでCommand Line Toolsをインストールし、ターミナルでlldb --replを実行します。LLDBは/Library/Developer/CommandLineTools/usr/bin/にあります。
はい。lldb --attach-pid PIDまたはprocess attach --name AppNameで可能です。LLDBがプロセスを一時停止し、その後アプリケーションを再起動せずにすべての標準デバッグコマンドが使用可能になります。
dSYMデバッグ情報ファイルが不足しています。Build Settingsを確認してください。Generate Debug SymbolsをYES、Debug Information FormatをDWARF with dSYM Fileに設定する必要があります。
LLDBは自動的に履歴を~/.lldb/lldb-historyに保存します。エクスポートするにはsession save filename.txtを使用します。このコマンドは現在のセッションで実行されたすべてのコマンドをテキストファイルに保存します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。