LLDB: co to za debugger, podstawowe polecenia i zastosowanie w programowaniu iOS

Autor: IT Sectr Opublikowano: 2026-05-07 Czas czytania: 9 min

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 — standardowy debugger Xcode z otwartym kodem źródłowym oparty na narzędziach LLVM.
  • Modułowa architektura LLDB składa się z bibliotek do parsowania, wykonywania i wizualizacji, niezależnych od siebie.
  • Polecenia LLDB pozwalają ustawiać breakpoints, inspekcjonować zmienne, wykonywać wyrażenia i zmieniać stan podczas debugowania.
  • Python API LLDB umożliwia tworzenie niestandardowych skryptów do automatyzacji scenariuszy debugowania.
  • Tryb REPL LLDB działa jako interaktywne środowisko do eksperymentowania z kodem w Swift i C.

Czym jest LLDB i jak jest zbudowany

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.

Historia i ewolucja

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: moduły i komponenty

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 LLDBPrzeznaczenieBiblioteka
CoreZarządzanie procesem debugowania, zdarzenia, stany wątkówliblldbCore.dylib
Expression ParserParsowanie i wykonywanie wyrażeń (C/C++/ObjC/Swift)liblldbExpression.dylib
Symbol FileOdczyt DWARF, Mach-O, dSYM — praca z informacją debugowanialiblldbSymbol.dylib
Target ControlZarządzanie wykonaniem: uruchamianie, zatrzymywanie, krokiliblldbTarget.dylib
InterpreterWiersz poleceń i tryb REPLliblldbInterpreter.dylib

LLDB i symbole debugowania dSYM

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
(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

Podstawowe polecenia LLDB do debugowania

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.

Polecenia zarządzania wykonaniem

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
(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

Inspekcja danych i formatery

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
(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ń i inspekcja obiektów

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.

Polecenia expression i po

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
(lldb) expr -l Swift -- UIAlertController(title: "Test", message: nil,
  preferredStyle: .alert)
(lldb) expr let $arr = [1, 2, 3].map { $0 * 2 }
(lldb) po $arr3 elements
  - 0 : 2
  - 1 : 4
  - 2 : 6

Modyfikacja obiektów w locie

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
(lldb) expr self.label.text = @"Updated"
(lldb) expr -l Swift -- (self as! UIViewController).view.backgroundColor = .red
(lldb) expr let $snapshot = self.view.debugQuickLookObject()

Skryptowanie w Pythonie w LLDB

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.

Tworzenie niestandardowego polecenia

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.

python
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}")

Obsługa zdarzeń breakpoints

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
(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])"

Tryb REPL i playground

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
(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.

Wykorzystanie REPL do nauki Swift

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

Czym LLDB różni się od GDB?

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.

Jak uruchomić LLDB REPL na macOS bez Xcode?

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/.

Czy można podłączyć LLDB do już uruchomionego procesu?

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.

Dlaczego LLDB nie pokazuje kodu źródłowego, a tylko asembler?

Brakuje plików dSYM informacji debugowania. Sprawdź ustawienia Build Settings: Generate Debug Symbols powinien być YES, a Debug Information FormatDWARF with dSYM File.

Jak zapisać historię poleceń LLDB?

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

  • LLDB — debugger nowej generacji projektu LLVM, standardowy dla Xcode i całego ekosystemu Apple.
  • Modułowa architektura z bibliotekami Core, Expression Parser, Symbol File i Interpreter.
  • Polecenia LLDB dzielą się na zarządzanie wykonaniem, breakpoints, inspekcję danych i obliczanie wyrażeń.
  • Obliczanie wyrażeń w locie — kluczowa możliwość pozwalająca testować kod bez restartu.
  • Python API daje pełną kontrolę nad debuggerem przez skrypty: niestandardowe polecenia, obsługa breakpoints, raporty.
  • Tryb REPL działa jako interaktywny playground dla Swift i C, przydatny do nauki i prototypowania.
  • Pliki dSYM są niezbędne do symbolizacji crash-logów i poprawnego wyświetlania kodu źródłowego.

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.

Omów projekt

Przeczytaj również