LLDB (Low-Level Debugger) is a next-generation debugger from the LLVM project, included in Xcode for debugging applications on iOS, macOS, tvOS, and watchOS. Unlike GDB, LLDB uses a modular architecture with the LLVM compiler, providing high speed and accuracy. According to the LLVM Project, LLDB supports debugging in C, Objective-C, C++, and Swift with a full set of features: breakpoints, watchpoints, memory inspection, and step-by-step execution.
Key Takeaways
LLDB is an open-source debugger built on the LLVM project libraries. It replaced GDB in Xcode 5 and has since become the primary debugging tool for the entire Apple ecosystem. Unlike the monolithic GDB, LLDB is implemented as a set of interacting libraries: each function — from expression parsing to memory management — is placed in a separate module, simplifying maintenance and extension.
Key LLDB capabilities include: setting breakpoints of any type, watchpoints for tracking variable changes, memory and register inspection, step-by-step execution, evaluating arbitrary expressions in the context of a stopped program, and running Python scripts for automation. According to the LLVM repository, LLDB supports over 200 debug commands and is compatible with DWARF and Mach-O formats — the main debug information formats in the Apple ecosystem.
An important advantage of LLDB is its deep integration with Clang. By using the same compiler for parsing and compiling source code, LLDB can evaluate C++ and Objective-C expressions with accuracy unavailable in GDB. For Swift debugging, LLDB uses a separate Swift Language Runtime module that understands the language semantics: optional types, protocols, generics, and memory management through ARC.
The first version of LLDB appeared in 2010 as part of LLVM 2.8. By 2013, it had completely replaced GDB in Xcode. In 2019, with the release of Xcode 11, LLDB gained support for Swift Error Breakpoints and an improved expression parser for Swift. According to Apple, since iOS 14, the entire debugging stack for the simulator also works through LLDB, confirming its status as the platform's primary debugging tool.
LLDB architecture is built on the microservices principle: each subsystem exists as a separate library (dylib), connected to others through a common API. This distinguishes it from GDB, where all functions are combined into a single binary. The modular structure allows using LLDB components independently — for example, the expression parser can be embedded in an IDE without connecting the full debugger.
| LLDB Component | Purpose | Library |
|---|---|---|
| Core | Debug process management, events, thread states | liblldbCore.dylib |
| Expression Parser | Parsing and executing expressions (C/C++/ObjC/Swift) | liblldbExpression.dylib |
| Symbol File | Reading DWARF, Mach-O, dSYM — working with debug information | liblldbSymbol.dylib |
| Target Control | Execution control: launch, stop, steps | liblldbTarget.dylib |
| Interpreter | Command line and REPL mode | liblldbInterpreter.dylib |
dSYM are debug information files that Xcode generates during build. LLDB uses them to map machine code to source code: without dSYM, the debugger only shows memory addresses instead of function names and code lines. For App Store applications, dSYM files are uploaded separately to Apple's server and used to symbolize crash logs received from users through 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 commands are divided into several categories: execution control, breakpoint management, data inspection, and memory manipulation. Unlike the Xcode GUI, the LLDB console gives full control over debugging and allows operations unavailable through the graphical interface — for example, changing a variable's value on the fly or bulk editing breakpoints.
Continue, Step Over, Step Into, Step Out — the basis of the debug cycle. continue resumes execution until the next breakpoint. step over executes the current line entirely. step into goes inside the called method. step out completes the current function and returns control to the calling code. Additionally, there is step with type filter — stepping until the specified data type.
(lldb) thread backtrace # Show the call stack
* 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 # Show local variables
(Int) userId = 42
(String) endpoint = "https://api.example.com/user/42"
(lldb) thread step-over # Step Over
(lldb) thread step-in # Step Into
LLDB provides commands for viewing data in any format: memory read, frame variable, target variable. The special syntax po (print object) calls debugDescription on Objective-C objects and description on Swift types. Custom formatters are set via type summary add — useful for debugging complex structures such as CGRect or IndexPath.
(lldb) po userProfile # Print the object description
<UserProfile: 0x600000c4b80>
- name: "John"
- age: 30
- email: "john@example.com"
(lldb) expression userProfile.age = 31 # Change the value
(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
Expression evaluation in LLDB is one of the most powerful features, absent in GDB at the time of its dominance. LLDB can execute arbitrary code in C, Objective-C, C++, and Swift in the context of a stopped program, including calling methods, creating objects, and modifying state. This allows testing hypotheses without restarting the application and recompiling.
The expression command compiles and executes an expression at runtime of the debugged process. The -O flag (object description) triggers po. For multi-line expressions, use expression -l Swift --. LLDB compiles code on the fly via Clang or Swift Compiler, integrates the result into the current context, and returns the value. According to Apple, an expression compiles in 10–50 ms depending on complexity.
(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 allows not only reading but also modifying the state of objects and variables during debugging. This is critical for testing edge cases: you can set a variable to nil, change a UI element's color, or substitute a server response directly in the debugger, without recompiling and restarting. This technique is widely used in game development and applications with long flows, where restarting takes a lot of time.
(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 in LLDB allows writing scripts for debugging automation. Through Python, you can create custom commands, handle breakpoint events, generate reports, and even override debugger behavior. The built-in Python 3 interpreter runs directly inside LLDB, having access to the full debugging API through the lldb module.
You can register a new LLDB command via the @classmethod decorator in a Python script. After importing the script, the command becomes available as a built-in. For example, the printvars command can output all variables of the current frame with their types and values, formatted for a specific project. Automation reduces typical debug operations time by 60–80%, according to a survey of iOS developers on 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}")
Through the Python API, you can bind a script to breakpoint firing. Set a breakpoint, then run breakpoint command add and specify a Python function. This allows automatically logging state, sending data to analytics, or checking invariants without manual intervention. According to LLVM, this approach is used in Apple's infrastructure for collecting performance metrics during development.
(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) is an interactive LLDB mode, invoked with the lldb --repl command or through the Xcode Debug Console. In REPL, you can execute Swift or C code as in a playground, with instant feedback. LLDB compiles each line, executes it, and shows the result — convenient for experimenting with APIs, prototyping algorithms, and learning new language features without creating a project.
(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 mode also supports loading modules and frameworks via import. For example, import UIKit in REPL loads the entire UIKit library, allowing you to create UI elements, check constraints, and test animations. This is a unique capability for iOS developers, unavailable in GDB — debugging and prototyping in one environment.
Thanks to integration with the Swift Compiler, LLDB REPL is used in Apple courses for teaching Swift. Students can execute code line by line, see types and results without being distracted by project setup. This approach follows the Active Learning methodology, where interactive feedback accelerates material comprehension by 40% according to research in Computer Science Education.
Frequently Asked Questions
LLDB is built on a modular LLVM architecture, giving it an advantage in expression evaluation speed and support for modern languages (Swift). GDB is a monolithic debugger that does not support Swift and has limited scripting capabilities.
Install Command Line Tools via xcode-select --install, then run lldb --repl in the terminal. LLDB is available at /Library/Developer/CommandLineTools/usr/bin/.
Yes, via lldb --attach-pid PID or process attach --name AppName. LLDB will pause the process, after which all standard debug commands are available without restarting the application.
dSYM debug information files are missing. Check Build Settings: Generate Debug Symbols must be YES, and Debug Information Format must be DWARF with dSYM File.
LLDB automatically saves history to ~/.lldb/lldb-history. For export, use session save filename.txt — the command saves all executed commands of the current session to a text file.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also