LLDB

デバッグSwiftC/C++Objective-CXcodeAppleLLVMiOSmacOS

デバッグツール

LLDB

概要

LLDBは、LLVMプロジェクトの高性能デバッガーです。C、C++、Objective-C、Swiftに対応し、XcodeのデフォルトデバッガーとしてmacOS/iOS開発で標準的に使用されています。

詳細

LLDB(Low-Level Debugger)は、LLVM(Low Level Virtual Machine)プロジェクトの一部として開発された次世代の高性能デバッガーです。2010年にAppleが中心となって開発を開始し、現在ではXcode 5以降のデフォルトデバッガーとして採用されています。LLDBは、C、C++、Objective-C、Swiftなど複数の言語をサポートし、特にSwift言語との統合において優れた機能を提供します。

Apple環境での標準デバッガーとして、Swift言語の普及とともに重要性が増加しており、macOS、iOS、watchOS、tvOSの開発において不可欠なツールとなっています。また、Linux環境でも徐々に採用が広がっており、クロスプラットフォーム対応も進んでいます。

2024年の最新機能では、Swift 6の@DebugDescriptionマクロサポートにより、pコマンドや変数ビューアーの出力をソースコードから直接カスタマイズできるようになりました。LLDBは完全機能のSwiftとClangコンパイラーを内蔵し、式評価器(expression evaluator)を通じて、変数の参照を超えた計算の実行、関数の呼び出し、プログラム状態の変更が可能です。

PythonスクリプトAPIを提供し、繰り返し作業の自動化、深くネストしたオブジェクトの検査、変数の動的操作など高度なデバッグワークフローを実現できます。Swift REPLとの緊密な統合により、インタラクティブな開発とデバッグ体験を提供しています。

メリット・デメリット

メリット

  • 高速パフォーマンス: LLVMアーキテクチャによる優秀な実行性能
  • Swift完全対応: Swiftデバッグに最適化された専用機能
  • Xcode統合: Apple開発環境でのシームレスな統合
  • 豊富な式評価: フル機能のコンパイラーによる高度な式評価
  • Pythonスクリプティング: 強力な自動化とカスタマイズ機能
  • REPL統合: Swift REPLとの緊密な統合
  • クロスプラットフォーム: macOS、Linux、FreeBSD、Windowsで動作
  • モダンアーキテクチャ: 最新のデバッグ技術と設計パターン

デメリット

  • Apple環境依存: 主にApple開発エコシステムに特化
  • 学習コスト: GDBとは異なるコマンド体系の習得が必要
  • ドキュメント不足: GDBに比べてチュートリアル資料が少ない
  • Linux対応の限界: Linux環境での機能制限
  • 設定の複雑さ: 高度な機能利用時の設定が煩雑
  • メモリ使用量: 高機能な分、メモリ消費が大きい
  • コミュニティの小ささ: GDBに比べてコミュニティが小規模

主要リンク

書き方の例

LLDBの起動と基本操作

# プログラムをLLDBで起動
lldb ./myprogram

# 実行中のプロセスにアタッチ
lldb -p <process_id>

# Swift REPLモード起動
swift
# または
lldb --repl

# コアダンプ解析
lldb -c core ./myprogram

基本的なLLDBコマンド

# プログラム実行
(lldb) run
(lldb) r

# 引数付きで実行
(lldb) run arg1 arg2
(lldb) settings set target.run-args arg1 arg2

# ブレークポイント設定
(lldb) breakpoint set --name main
(lldb) b main
(lldb) breakpoint set --file main.swift --line 25
(lldb) br s -f main.swift -l 25

# ブレークポイント一覧
(lldb) breakpoint list
(lldb) br list

# ブレークポイント削除
(lldb) breakpoint delete 1
(lldb) br del 1

プログラム実行制御

# ステップイン(関数内に入る)
(lldb) step
(lldb) s

# ステップオーバー(関数をまたぐ)
(lldb) next
(lldb) n

# ステップアウト(関数から出る)
(lldb) finish
(lldb) f

# 実行継続
(lldb) continue
(lldb) c

# 指定行まで実行
(lldb) thread until 30

変数とメモリの検査

# 変数の値表示
(lldb) print variable_name
(lldb) p variable_name
(lldb) po object_name        # オブジェクトの説明

# Swift変数の詳細表示
(lldb) v variable_name       # 変数の詳細
(lldb) fr var               # フレーム内の全変数

# メモリ読み取り
(lldb) memory read 0x12345678
(lldb) mem read -s 1 -f x -c 16 0x12345678

# 変数の値変更
(lldb) expr variable_name = new_value
(lldb) expression -- variable_name = new_value

バックトレースとスタック情報

# バックトレース表示
(lldb) thread backtrace
(lldb) bt

# 全スレッドのバックトレース
(lldb) thread backtrace all
(lldb) bt all

# スタックフレーム選択
(lldb) frame select 0
(lldb) f 0

# フレーム情報表示
(lldb) frame info
(lldb) frame variable        # フレーム内変数

Swiftデバッグ専用機能

# Swift式の評価
(lldb) expression let result = someFunction()
(lldb) expr -l swift -- let x = 10

# Swiftオブジェクトのダンプ
(lldb) po myObject
(lldb) expr -O -- myObject

# Swift型情報表示
(lldb) type lookup Swift.String
(lldb) image lookup -t String

# Swift REPL呼び出し
(lldb) repl

高度なデバッグ機能

# 条件付きブレークポイント
(lldb) breakpoint set --name main --condition 'argc > 1'
(lldb) br s -n main -c 'argc > 1'

# ウォッチポイント
(lldb) watchpoint set variable variable_name
(lldb) wa s v variable_name

# 例外ブレークポイント
(lldb) breakpoint set -E swift
(lldb) breakpoint set -E objc

# 関数呼び出し
(lldb) call function_name(args)
(lldb) expression function_name(args)

スレッドとプロセス管理

# スレッド一覧
(lldb) thread list

# スレッド切り替え
(lldb) thread select 2

# プロセス情報
(lldb) process status
(lldb) process continue
(lldb) process kill

# シグナル処理
(lldb) process handle SIGINT -s true -p true

LLDBカスタマイゼーション

# カスタムコマンド定義(~/.lldbinit)
command alias bd breakpoint disable
command alias be breakpoint enable

# Pythonスクリプト
script
import lldb

def hello_command(debugger, command, result, internal_dict):
    print("Hello from LLDB!")

lldb.debugger.HandleCommand('command script add -f script.hello_command hello')
script

# 設定変更
(lldb) settings set target.x86-disassembly-flavor intel
(lldb) settings set thread-format "thread #${thread.index}: tid = ${thread.id}{, pc = ${frame.pc}}"

iOS/macOS開発での実用例

# ViewControllerのプロパティ確認
(lldb) po self.view
(lldb) po [self.view recursiveDescription]

# UIの実行時変更
(lldb) expr self.view.backgroundColor = UIColor.red
(lldb) expr (void)[CATransaction flush]

# Core Dataオブジェクトの確認
(lldb) po managedObjectContext.registeredObjects

# Swift Concurrency デバッグ
(lldb) thread list
(lldb) bt

Pythonスクリプトによる自動化

# ~/.lldbinit または独立したPythonファイル
import lldb

def print_all_variables(debugger, command, result, internal_dict):
    target = debugger.GetSelectedTarget()
    process = target.GetProcess()
    thread = process.GetSelectedThread()
    frame = thread.GetSelectedFrame()
    
    variables = frame.GetVariables(True, True, True, True)
    for var in variables:
        print(f"{var.name} = {var.value}")

def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand('command script add -f mymodule.print_all_variables pav')

式評価とREPLの活用

# 複雑な式の評価
(lldb) expr import Foundation
(lldb) expr let url = URL(string: "https://example.com")
(lldb) po url

# 一時関数の定義と実行
(lldb) expr func debugHelper() -> String { return "Debug info" }
(lldb) po debugHelper()

# インラインでのSwiftコード実行
(lldb) expr -l swift -- 
    let formatter = DateFormatter()
    formatter.dateStyle = .full
    print(formatter.string(from: Date()))