LLDB (Low-Level Debugger) — debugger nowej generacji projektu LLVM, wchodzący w skład Xcode do debugowania aplikacji na iOS, macOS, tvOS i watchOS. W przeciwieństwie do GDB, LLDB wykorzystuje modułową architekturę z kompilatorem LLVM, co zapewnia wysoką szybkość i dokładność. Według danych LLVM Project, LLDB obsługuje debugowanie w językach C, Objective-C, C++ i Swift z pełnym zestawem funkcji: breakpoints, watchpoints, inspekcja pamięci i wykonanie krokowe.
Najważniejsze
LLDB — to debugger z otwartym kodem źródłowym, zbudowany na bibliotekach projektu LLVM. Zastąpił GDB w Xcode 5 i od tego czasu jest głównym narzędziem debugowania dla całego ekosystemu Apple. W przeciwieństwie do monolitycznego GDB, LLDB jest zaimplementowany jako zestaw współdziałających bibliotek: każda funkcja — od parsowania wyrażeń po pracę z pamięcią — została wydzielona do osobnego modułu, co ułatwia utrzymanie i rozszerzanie.
Podstawowe możliwości LLDB obejmują: ustawianie breakpoints dowolnego typu, watchpoints do śledzenia zmian zmiennych, inspekcję pamięci i rejestrów, wykonanie krokowe, obliczanie dowolnych wyrażeń w kontekście zatrzymanego programu oraz wykonywanie skryptów Python do automatyzacji. Według danych repozytorium LLVM, LLDB obsługuje ponad 200 poleceń debugowania i jest zgodny z formatami DWARF i Mach-O — podstawowymi formatami informacji debugowania w ekosystemie Apple.
Ważną zaletą LLDB jest głęboka integracja z Clang. Dzięki wykorzystaniu tego samego kompilatora do parsowania i kompilacji kodu źródłowego, LLDB może obliczać wyrażenia C++ i Objective-C z dokładnością niedostępną dla GDB. Do debugowania Swift LLDB używa osobnego modułu Swift Language Runtime, który rozumie semantykę języka: typy opcjonalne, protokoły, typy generyczne i zarządzanie pamięcią przez ARC.
Pierwsza wersja LLDB pojawiła się w 2010 roku jako część LLVM 2.8. Do 2013 roku całkowicie zastąpił GDB w Xcode. W 2019 roku wraz z wydaniem Xcode 11 LLDB otrzymał wsparcie dla Swift Error Breakpoints i ulepszony parser wyrażeń dla Swift. Według danych Apple, od iOS 14 cały stos debugowania dla symulatora również działa przez LLDB, co potwierdza jego status głównego narzędzia debugowania platformy.
Architektura LLDB jest zbudowana na zasadzie mikrousług: każdy podsystem istnieje jako osobna biblioteka (dylib), połączona z innymi poprzez wspólne API. To odróżnia go od GDB, gdzie wszystkie funkcje są połączone w jeden plik binarny. Modułowa struktura pozwala na niezależne wykorzystanie komponentów LLDB — na przykład parser wyrażeń można wbudować w IDE bez podłączania pełnego debuggera.
| Komponent LLDB | Przeznaczenie | Biblioteka |
|---|---|---|
| Core | Zarządzanie procesem debugowania, zdarzenia, stany wątków | liblldbCore.dylib |
| Expression Parser | Parsowanie i wykonywanie wyrażeń (C/C++/ObjC/Swift) | liblldbExpression.dylib |
| Symbol File | Odczyt DWARF, Mach-O, dSYM — praca z informacją debugowania | liblldbSymbol.dylib |
| Target Control | Zarządzanie wykonaniem: uruchamianie, zatrzymywanie, kroki | liblldbTarget.dylib |
| Interpreter | Wiersz poleceń i tryb REPL | liblldbInterpreter.dylib |
dSYM — to pliki informacji debugowania, które Xcode generuje podczas kompilacji. LLDB używa ich do mapowania kodu maszynowego na kod źródłowy: bez dSYM debugger pokazuje tylko adresy w pamięci zamiast nazw funkcji i linii kodu. Dla aplikacji z App Store pliki dSYM są przesyłane osobno na serwer Apple i używane do symbolizacji crash-logów otrzymanych od użytkowników przez 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
Polecenia LLDB dzielą się na kilka kategorii: zarządzanie wykonaniem, praca z breakpoints, inspekcja danych i manipulacja pamięcią. W przeciwieństwie do Xcode GUI, konsola LLDB daje pełną kontrolę nad debugowaniem i pozwala wykonywać operacje niedostępne przez interfejs graficzny — na przykład zmianę wartości zmiennej w locie lub masową edycję breakpoints.
Continue, Step Over, Step Into, Step Out — podstawa cyklu debugowania. continue wznawia wykonanie do następnego breakpoint. step over wykonuje bieżącą linię w całości. step into wchodzi do wnętrza wywoływanej metody. step out kończy bieżącą funkcję i zwraca sterowanie do kodu wywołującego. Dodatkowo istnieje step with type filter — krok do określonego typu danych.
(lldb) thread backtrace # Pokaż stos wywołań
* 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 # Pokaż zmienne lokalne
(Int) userId = 42
(String) endpoint = "https://api.example.com/user/42"
(lldb) thread step-over # Step Over
(lldb) thread step-in # Step Into
LLDB udostępnia polecenia do przeglądania danych w dowolnym formacie: memory read, frame variable, target variable. Specjalna składnia po (print object) wywołuje debugDescription dla obiektów Objective-C i description dla typów Swift. Niestandardowe formatery ustawia się przez type summary add — przydatne do debugowania złożonych struktur, takich jak CGRect czy IndexPath.
(lldb) po userProfile # Wyświetlenie opisu obiektu
<UserProfile: 0x600000c4b80>
- name: "John"
- age: 30
- email: "john@example.com"
(lldb) expression userProfile.age = 31 # Zmień wartość
(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
Obliczanie wyrażeń w LLDB to jedna z najpotężniejszych funkcji, której brakowało w GDB w czasie jego dominacji. LLDB może wykonywać dowolny kod w C, Objective-C, C++ i Swift w kontekście zatrzymanego programu, w tym wywoływanie metod, tworzenie obiektów i modyfikację stanu. Pozwala to testować hipotezy bez restartowania aplikacji i ponownej kompilacji.
Polecenie expression kompiluje i wykonuje wyrażenie w czasie wykonywania debugowanego procesu. Flaga -O (object description) wywołuje po. Dla wyrażeń wieloliniowych użyj expression -l Swift --. LLDB kompiluje kod w locie przez Clang lub Swift Compiler, integruje wynik z bieżącym kontekstem i zwraca wartość. Według danych Apple, wyrażenie jest kompilowane w 10–50 ms w zależności od złożoności.
(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 pozwala nie tylko czytać, ale także zmieniać stan obiektów i zmiennych podczas debugowania. Jest to kluczowe do testowania przypadków brzegowych: można ustawić wartość zmiennej na nil, zmienić kolor elementu UI lub podmienić odpowiedź serwera bezpośrednio w debuggerze, bez ponownej kompilacji i restartu. Technika ta jest szeroko stosowana w tworzeniu gier i aplikacji z długimi przepływami, gdzie restart zajmuje dużo czasu.
(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 pozwala pisać skrypty do automatyzacji debugowania. Przez Python można tworzyć niestandardowe polecenia, obsługiwać zdarzenia breakpoint, generować raporty, a nawet nadpisywać zachowanie debuggera. Wbudowany interpreter Python 3 uruchamia się bezpośrednio wewnątrz LLDB, mając dostęp do pełnego API debugowania przez moduł lldb.
Zarejestrować nowe polecenie LLDB można przez dekorator @classmethod w skrypcie Python. Po zaimportowaniu skryptu polecenie staje się dostępne jak wbudowane. Na przykład polecenie printvars może wyświetlać wszystkie zmienne bieżącej ramki z ich typami i wartościami, sformatowanymi dla konkretnego projektu. Automatyzacja skraca czas typowych operacji debugowania o 60–80%, według ankiety wśród programistów iOS na 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}")
Przez Python API można przypisać skrypt do wyzwolenia breakpoint. Ustaw breakpoint, następnie wykonaj breakpoint command add i podaj funkcję Python. Pozwala to automatycznie logować stan, wysyłać dane do analityki lub sprawdzać niezmienniki bez ręcznej interwencji. Według danych LLVM, takie podejście jest używane w infrastrukturze Apple do zbierania metryk wydajności na etapie tworzenia oprogramowania.
(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) — tryb interaktywny LLDB, wywoływany poleceniem lldb --repl lub przez Xcode Debug Console. W REPL można wykonywać kod w Swift lub C jak w playground, z natychmiastową informacją zwrotną. LLDB kompiluje każdą linię, wykonuje ją i pokazuje wynik — jest to wygodne do eksperymentowania z API, prototypowania algorytmów i nauki nowych możliwości języka bez tworzenia projektu.
(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
Tryb REPL obsługuje również ładowanie modułów i frameworków przez import. Na przykład import UIKit w REPL ładuje całą bibliotekę UIKit, co pozwala tworzyć elementy UI, sprawdzać constrainty i testować animacje. To unikalna możliwość dla programistów iOS, niedostępna w GDB — debugowanie i prototypowanie w jednym środowisku.
Dzięki integracji z Swift Compiler, LLDB REPL jest używany na kursach Apple do nauki Swift. Studenci mogą wykonywać kod linia po linii, widzieć typy i wyniki, nie rozpraszając się konfiguracją projektu. Takie podejście jest zgodne z metodą Active Learning, gdzie interaktywna informacja zwrotna przyspiesza przyswajanie materiału o 40% według badań z zakresu Computer Science Education.
Często zadawane pytania
LLDB jest zbudowany na modułowej architekturze LLVM, co daje mu przewagę w szybkości pracy z wyrażeniami i wsparciu nowoczesnych języków (Swift). GDB to monolityczny debugger, który nie obsługuje Swift i ma ograniczone możliwości skryptowania.
Zainstaluj Command Line Tools przez xcode-select --install, następnie wykonaj lldb --repl w terminalu. LLDB jest dostępny w /Library/Developer/CommandLineTools/usr/bin/.
Tak, przez lldb --attach-pid PID lub process attach --name AppName. LLDB wstrzyma proces, po czym dostępne są wszystkie standardowe polecenia debugowania bez restartowania aplikacji.
Brakuje plików dSYM informacji debugowania. Sprawdź ustawienia Build Settings: Generate Debug Symbols powinien być YES, a Debug Information Format — DWARF with dSYM File.
LLDB automatycznie zapisuje historię w ~/.lldb/lldb-history. Do eksportu użyj session save filename.txt — polecenie zapisuje wszystkie wykonane polecenia bieżącej sesji do pliku tekstowego.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również