LLDB (Low-Level Debugger) — дебъгер от ново поколение на LLVM проекта, който е част от Xcode за дебъгване на приложения за iOS, macOS, tvOS и watchOS. За разлика от GDB, LLDB използва модулна архитектура с LLVM компилатор, което осигурява висока скорост и точност. Според данните на LLVM Project, LLDB поддържа дебъгване на езиците C, Objective-C, C++ и Swift с пълен набор от функции: breakpoints, watchpoints, инспекция на паметта и изпълнение стъпка по стъпка.
Основни точки
LLDB — е дебъгер с отворен код, изграден върху библиотеките на LLVM проекта. Той замени GDB в Xcode 5 и оттогава е основният инструмент за дебъгване на цялата екосистема на Apple. За разлика от монолитния GDB, LLDB е имплементиран като набор от взаимодействащи си библиотеки: всяка функция — от парсване на изрази до работа с памет — е отделена в самостоятелен модул, което опростява поддръжката и разширяването.
Основните възможности на LLDB включват: задаване на breakpoints от всякакъв тип, watchpoints за проследяване на промени в променливи, инспекция на памет и регистри, изпълнение стъпка по стъпка, изчисляване на произволни изрази в контекста на спряна програма и изпълнение на Python скриптове за автоматизация. Според хранилището на LLVM, LLDB поддържа над 200 команди за дебъгване и е съвместим с форматите DWARF и Mach-O — основните формати за дебъг информация в екосистемата на Apple.
Важно предимство на LLDB е дълбоката интеграция с Clang. Благодарение на използването на един и същ компилатор за парсване и компилиране на изходния код, LLDB може да изчислява C++ и Objective-C изрази с точност, недостъпна за GDB. За дебъгване на Swift, LLDB използва отделен модул Swift Language Runtime, който разбира семантиката на езика: опционални типове, протоколи, генерични типове и управление на паметта чрез ARC.
Първата версия на LLDB се появи през 2010 г. като част от LLVM 2.8. До 2013 г. той напълно замени GDB в Xcode. През 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 сървъра и се използват за символизация на crash-логове, получени от потребители чрез 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 се разделят на няколко категории: управление на изпълнението, работа с breakpoints, инспекция на данни и манипулиране на паметта. За разлика от графичния интерфейс на Xcode, конзолата на LLDB дава пълен контрол върху дебъгването и позволява извършване на операции, недостъпни чрез графичния интерфейс — например, промяна на стойността на променлива в движение или масово редактиране на breakpoints.
Continue, Step Over, Step Into, Step Out — основата на цикъла на дебъгване. continue възобновява изпълнението до следващия breakpoint. 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) извиква debugDescription при Objective-C обекти и description при Swift типове. Персонализирани форматиращи програми се задават чрез 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 е една от най-мощните функции, която липсваше в GDB по времето на неговото доминиране. LLDB може да изпълнява произволен код на C, Objective-C, C++ и Swift в контекста на спряна програма, включително извикване на методи, създаване на обекти и модифициране на състояние. Това позволява тестване на хипотези без рестартиране на приложението и прекомпилиране.
Командата expression компилира и изпълнява израз по време на изпълнение на дебъгвания процес. Флагът -O (object description) извиква po. За многоредови изрази използвайте expression -l Swift --. LLDB компилира код в движение чрез Clang или Swift Compiler, интегрира резултата в текущия контекст и връща стойността. Според Apple, изразът се компилира за 10–50 ms в зависимост от сложността.
(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()
Python API на LLDB позволява писане на скриптове за автоматизиране на дебъгването. Чрез Python могат да се създават персонализирани команди, да се обработват събития на breakpoint, да се генерират отчети и дори да се презаписва поведението на дебъгера. Вграденият интерпретатор на Python 3 стартира директно в LLDB, с достъп до пълния API за дебъгване чрез модула lldb.
Нова команда на LLDB може да бъде регистрирана чрез декоратора @classmethod в Python скрипт. След импортиране на скрипта, командата става достъпна като вградена. Например, командата printvars може да покаже всички променливи на текущата рамка с техните типове и стойности, форматирани за конкретен проект. Автоматизацията намалява времето за типични дебъг операции с 60–80%, според анкета сред iOS разработчици в Stack Overflow.
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. Задайте breakpoint, след това изпълнете 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 Debug Console. В REPL можете да изпълнявате код на Swift или C като в playground, с незабавна обратна връзка. 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. Например, import UIKit в REPL зарежда цялата UIKit библиотека и можете да създавате UI елементи, да проверявате ограничения и да тествате анимации. Това е уникална възможност за iOS разработчици, недостъпна в GDB — дебъгване и прототипиране в една среда.
Благодарение на интеграцията с Swift Compiler, LLDB REPL се използва в курсовете на Apple за обучение по Swift. Студентите могат да изпълняват код ред по ред, да виждат типове и резултати, без да се разсейват с конфигуриране на проект. Този подход съответства на метода Active Learning, където интерактивната обратна връзка ускорява усвояването на материала с 40% според изследвания в областта на Computer Science Education.
Често задавани въпроси
LLDB е изграден върху модулна LLVM архитектура, което му дава предимство в скоростта на работа с изрази и поддръжката на съвременни езици (Swift). GDB е монолитен дебъгер, който не поддържа Swift и има ограничени възможности за скриптове.
Инсталирайте Command Line Tools чрез xcode-select --install, след това изпълнете 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 създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също