Crash Debugging Skill
Comprehensive guide to iOS crash analysis and debugging
Quick Reference
| Task | Tool/Command | Location | |------|--------------|----------| | View crash logs | Console.app | macOS Application | | Retrieve simulator crashes | ~/Library/Logs/DiagnosticReports/ | File system | | Symbolicate crash | atos | Command line | | Find dSYM files | Xcode Organizer / DerivedData | Xcode | | Analyze crash type | Stack trace patterns | Crash log |
Overview
Crash debugging transforms cryptic crash logs into actionable insights. This skill covers:
- Retrieving crash logs from simulators and devices
- Understanding crash log structure
- Symbolicating stack traces for readable function names
- Identifying common crash patterns
- Determining root causes
When to Use This Skill
Use this skill when:
- App crashes during testing or development
- Received crash reports from users or TestFlight
- CI/CD pipeline reports test crashes
- Need to symbolicate production crash logs
- Investigating memory issues or crashes
Don't use for:
- Build failures (see xcode-workflows)
- Test assertion failures (see ios-testing-patterns)
- UI debugging (see ui-automation-workflows)
Key Concepts
Crash Logs vs Diagnostic Reports
Crash Logs:
- Generated when app terminates unexpectedly
- Include exception type, stack trace, register state
- Stored in DiagnosticReports directory
- Named:
AppName_YYYY-MM-DD-HHMMSS_DeviceName.crash
Diagnostic Reports:
- Broader category including crashes, spins, hangs
- May include system diagnostics
- Same location as crash logs
Symbolication Process
Unsymbolicated:
0 MyApp 0x0000000102a3c4f8 0x102a38000 + 17656
1 MyApp 0x0000000102a3d1a4 0x102a38000 + 20900
Symbolicated:
0 MyApp 0x0000000102a3c4f8 ViewController.loginButtonTapped() + 120
1 MyApp 0x0000000102a3d1a4 ViewController.viewDidLoad() + 84
Symbolication Requirements:
- dSYM file matching the build UUID
- Binary (MyApp.app/MyApp)
- Crash log with memory addresses
Stack Traces and Debugging Symbols
Stack Trace:
- List of function calls leading to crash
- Ordered from crash point (top) to app entry (bottom)
- Each line contains: frame number, binary name, address, symbol + offset
Debugging Symbols (dSYM):
- Separate file containing symbol information
- Maps memory addresses to function names
- Generated during build (if "Debug Information Format" = "DWARF with dSYM")
- Essential for crash analysis
Common Crash Types
| Exception Type | Meaning | Common Cause | |----------------|---------|--------------| | EXC_BAD_ACCESS | Invalid memory access | Dangling pointer, use-after-free | | SIGABRT | Process aborted | Assertion failure, force unwrap nil | | EXC_BREAKPOINT | Breakpoint hit | Swift runtime error, fatal error | | SIGILL | Illegal instruction | Corrupted code, wrong architecture | | SIGSEGV | Segmentation fault | Memory corruption | | SIGBUS | Bus error | Unaligned memory access |
Workflows
Workflow 1: Crash Log Retrieval
From Simulator
Step 1: Locate Crash Logs
open ~/Library/Logs/DiagnosticReports/
Directory Structure:
DiagnosticReports/
├── MyApp_2025-11-06-143022_Conors-MacBook.crash
├── MyApp_2025-11-06-140511_Conors-MacBook.crash
└── ...
Step 2: Identify Recent Crash
Sort by date modified, or filter by app name:
ls -lt ~/Library/Logs/DiagnosticReports/ | grep MyApp | head -5
Step 3: Read Crash Log
cat ~/Library/Logs/DiagnosticReports/MyApp_2025-11-06-143022_Conors-MacBook.crash
From Console.app (Recommended)
Step 1: Open Console.app
open -a Console
Step 2: Filter Logs
- Click "Crash Reports" in sidebar
- Search for app name
- Click crash report to view
Advantages:
- Real-time monitoring
- Better filtering and search
- Automatic refresh
From Device (via Xcode)
Step 1: Connect Device
Step 2: Open Devices and Simulators
- Xcode → Window → Devices and Simulators
- Select device
Step 3: View Device Logs
- Click "View Device Logs"
- Find crash report
- Right-click → Export
Workflow 2: Symbolication
Automatic Symbolication (Xcode)
Step 1: Locate dSYM
Xcode automatically symbolicates if:
- dSYM is in Spotlight index
- dSYM UUID matches crash log
Check dSYM UUID:
dwarfdump --uuid /path/to/MyApp.app.dSYM
Check Crash Log UUID:
Binary Images:
0x102a38000 - 0x102a4bfff MyApp arm64 <12345678-1234-1234-1234-123456789abc>
UUIDs must match for symbolication.
Step 2: Import to Xcode
If auto-symbolication fails:
- Xcode → Window → Organizer
- Select "Crashes" tab
- Drag crash log into window
- Xcode symbolicates automatically (if dSYM available)
Manual Symbolication (atos)
Step 1: Find Required Files
# App binary
APP_BINARY="/path/to/MyApp.app/MyApp"
# dSYM file
DSYM_FILE="/path/to/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp"
# Load address (from crash log "Binary Images" section)
LOAD_ADDRESS="0x102a38000"
Step 2: Symbolicate Address
atos -arch arm64 -o "$DSYM_FILE" -l "$LOAD_ADDRESS" 0x0000000102a3c4f8
Output:
ViewController.loginButtonTapped() (in MyApp) (ViewController.swift:45)
Step 3: Symbolicate Multiple Addresses
atos -arch arm64 -o "$DSYM_FILE" -l "$LOAD_ADDRESS" \
0x0000000102a3c4f8 \
0x0000000102a3d1a4 \
0x0000000102a3e220
Batch Symbolication (symbolicatecrash)
Symbolicate Entire Crash Log:
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
symbolicatecrash MyApp.crash MyApp.app.dSYM > MyApp_symbolicated.crash
Verify Symbolication:
grep -A 10 "Thread 0 Crashed" MyApp_symbolicated.crash
Should show function names, not just addresses.
Workflow 3: Stack Trace Analysis
Reading a Crash Log
Crash Log Structure:
Incident Identifier: 12345678-1234-1234-1234-123456789ABC
CrashReporter Key: ABCDEF1234567890
Hardware Model: iPhone15,2
Process: MyApp [12345]
Path: /private/var/containers/Bundle/Application/.../MyApp.app/MyApp
Identifier: com.example.MyApp
Version: 1.0 (1)
Code Type: ARM-64
Parent Process: launchd [1]
Date/Time: 2025-11-06 14:30:22.123 +0000
OS Version: iOS 17.0 (21A5326a)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [12345]
Triggered by Thread: 0
Thread 0 Crashed:
0 MyApp 0x0000000102a3c4f8 ViewController.loginButtonTapped() + 120
1 MyApp 0x0000000102a3d1a4 ViewController.viewDidLoad() + 84
2 UIKitCore 0x00000001b2e4c3a0 -[UIViewController loadViewIfRequired] + 928
...
Thread 1:
0 libsystem_kernel.dylib 0x00000001a2b3c4a8 __workq_kernreturn + 8
...
Binary Images:
0x102a38000 - 0x102a4bfff MyApp arm64 <12345678-1234-1234-1234-123456789abc>
...
Key Sections to Analyze
1. Exception Type
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
- EXC_BAD_ACCESS: Memory access violation
- KERN_INVALID_ADDRESS: Address doesn't exist (null pointer)
- 0x0000000000000000: Accessing address zero (dereferencing nil)
2. Crashed Thread
Thread 0 Crashed:
0 MyApp 0x102a3c4f8 ViewController.loginButtonTapped() + 120
1 MyApp 0x102a3d1a4 ViewController.viewDidLoad() + 84
- Frame 0 is crash location
- Read from top to bottom (most recent to oldest)
- Identify last app frame before system frames
3. Binary Images
0x102a38000 - 0x102a4bfff MyApp arm64 <12345678-1234-1234-1234-123456789abc>
- Load address:
0x102a38000 - UUID:
12345678-1234-1234-1234-123456789abc - Architecture:
arm64
Workflow 4: Root Cause Identification
Step 1: Identify Crash Type
Match exception type to common patterns (see below).
Step 2: Locate Crash Point
Find the topmost frame in your app's code:
Thread 0 Crashed:
0 MyApp 0x102a3c4f8 ViewController.loginButtonTapped() + 120 ← START HERE
1 MyApp 0x102a3d1a4 ViewController.viewDidLoad() + 84
Step 3: Analyze Code Path
- Open file at crash location (ViewController.swift:45)
- Examine function
loginButtonTapped() - Check for:
- Optional unwrapping (
!or?) - Array/dictionary access
- Object references
- Memory management
- Optional unwrapping (
Step 4: Reproduce Locally
- Set breakpoint at crash location
- Follow stack trace path
- Inspect variables and state
- Identify null/invalid values
Step 5: Validate Fix
- Apply fix
- Build and test
- Verify no regression
- Monitor for related crashes
Common Crash Patterns
EXC_BAD_ACCESS (Memory Issues)
Signature:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
Common Causes:
1. Dereferencing Nil (Swift)
// Crash:
let user: User? = nil
let name = user!.name // EXC_BAD_ACCESS
// Fix:
if let name = user?.name {
// Use name safely
}
2. Dangling Pointer (Objective-C)
// Crash:
@property (nonatomic, unsafe_unretained) id delegate; // Dangerous
[self.delegate callMethod]; // Delegate deallocated → EXC_BAD_ACCESS
// Fix:
@property (nonatomic, weak) id<MyDelegate> delegate;
3. Use-After-Free
// Crash:
var buffer = UnsafeMutablePointer<Int>.allocate(capacity: 10)
buffer.deallocate()
buffer[0] = 42 // EXC_BAD_ACCESS
// Fix:
buffer[0] = 42
buffer.deallocate()
Debugging:
- Enable Address Sanitizer (Scheme → Diagnostics → Address Sanitizer)
- Check for
weakvsunsafe_unretainedreferences - Verify object lifecycle
SIGABRT (Assertion Failures)
Signature:
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 6 Abort trap: 6
Common Causes:
1. Force Unwrap Nil (Swift)
// Crash:
let value = dictionary["key"]! // key doesn't exist → SIGABRT
// Stack trace shows:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
// Fix:
if let value = dictionary["key"] {
// Use value
}
2. Array Index Out of Bounds
// Crash:
let items = [1, 2, 3]
let item = items[10] // Index out of range → SIGABRT
// Fix:
if items.indices.contains(10) {
let item = items[10]
}
3. NSException (Objective-C)
// Crash:
[NSException raise:@"InvalidState" format:@"Unexpected condition"];
// Stack trace shows:
*** Terminating app due to uncaught exception 'InvalidState'
Debugging:
- Read error message in crash log (very descriptive)
- Check preconditions and assertions
- Validate input data
EXC_BREAKPOINT (Swift Errors)
Signature:
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001a2b4c8d0
Common Causes:
1. Fatal Error
// Crash:
guard let user = currentUser else {
fatalError("User must be logged in") // EXC_BREAKPOINT
}
// Stack trace shows:
Fatal error: User must be logged in
// Fix:
guard let user = currentUser else {
print("Error: User not logged in")
return
}
2. Type Cast Failure (as!)
// Crash:
let value = anyValue as! String // Value is not String → EXC_BREAKPOINT
// Fix:
if let value = anyValue as? String {
// Use value
}
3. Precondition Failure
// Crash:
precondition(array.count > 0, "Array must not be empty")
// Fix:
if array.count > 0 {
// Proceed safely
}
Debugging:
- Read fatal error message in crash log
- Review force casts (
as!) - Check preconditions and guards
Timeout Crashes (Watchdog)
Signature:
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
0x8badf00d = "ate bad food" = Watchdog timeout
Common Causes:
1. Main Thread Blocking
// Crash:
func viewDidLoad() {
super.viewDidLoad()
Thread.sleep(forTimeInterval: 30) // Blocks main thread → Watchdog kills app
}
// Fix:
func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 30)
}
}
2. Launch Time Timeout
App takes too long to launch (>20 seconds).
Fix:
- Defer heavy initialization
- Use background queues
- Profile launch time
3. Suspend/Resume Timeout
App doesn't respond to backgrounding/foregrounding.
Fix:
- Implement
applicationDidEnterBackgroundquickly - Move long operations to background
Debugging:
- Instrument Time Profiler
- Check main thread operations
- Review app lifecycle methods
Memory Issues (JETSAM)
Signature:
Exception Type: EXC_RESOURCE
Exception Subtype: MEMORY
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: Namespace JETSAM, Code 0xdead10cc
Common Causes:
1. Memory Leak
// Leak:
class ViewController {
var closure: (() -> Void)?
func setup() {
closure = {
self.doSomething() // Retain cycle
}
}
}
// Fix:
closure = { [weak self] in
self?.doSomething()
}
2. Large Allocations
// Crash:
let hugeArray = Array(repeating: Data(count: 1_000_000), count: 1000)
// Fix:
// Process in chunks, release memory incrementally
Debugging:
- Instruments → Allocations
- Instruments → Leaks
- Memory Graph Debugger (Xcode)
Troubleshooting
Missing Symbols
Problem: Stack trace shows addresses, not function names
Cause: Missing or mismatched dSYM file
Solutions:
- Find Correct dSYM
# List all dSYMs in DerivedData
find ~/Library/Developer/Xcode/DerivedData -name "*.dSYM" -type d
# Check UUID
dwarfdump --uuid /path/to/MyApp.app.dSYM
- Match UUID
Compare dSYM UUID with crash log Binary Images UUID. They must match exactly.
- Archive dSYMs
Enable "Archive" in scheme settings to preserve dSYMs for releases.
- Download from Xcode Organizer
For App Store builds:
- Xcode → Window → Organizer
- Select archive
- Download dSYMs
Partial Stack Traces
Problem: Stack trace incomplete or truncated
Causes:
- Tail call optimization
- Inline functions
- Missing debug symbols
Solutions:
- Disable Optimizations
Build Settings:
- Optimization Level: None [-O0]
- Debug Information Format: DWARF with dSYM File
- Build with Debug Configuration
{
"operation": "build",
"scheme": "MyApp",
"configuration": "Debug"
}
- Disable Inlining
Add -Xswiftc -Ounchecked to reduce optimizations.
System Framework Crashes
Problem: Crash in UIKit, Foundation, or other system framework
Stack Trace:
Thread 0 Crashed:
0 UIKitCore 0x00001b2e4c3a0 -[UIView layoutSubviews] + 928
1 UIKitCore 0x00001b2e5d1c4 -[UIView setNeedsLayout] + 84
2 MyApp 0x00102a3c4f8 ViewController.updateUI() + 45
Analysis:
- Frame 2 is your code (start here)
- System frameworks rarely crash on their own
- Likely caused by invalid state or parameters from your code
Solutions:
- Check Parameters
Before system call, validate:
- Non-nil objects
- Valid ranges
- Correct types
- Review Constraints
Auto Layout issues often cause UIKit crashes:
- Check constraint conflicts
- Verify view hierarchy
- Enable Exception Breakpoint
Xcode → Breakpoints → + → Exception Breakpoint
- Catches issues before system framework crash
Third-Party Library Crashes
Problem: Crash in external library/framework
Stack Trace:
Thread 0 Crashed:
0 Alamofire 0x00001054a3c4f8 RequestAdapter.adapt() + 120
1 MyApp 0x00102a3c4f8 NetworkManager.fetchData() + 45
Solutions:
- Check Library Version
Ensure compatible version:
- Update to latest stable
- Check release notes for bug fixes
- Review Integration
Verify:
- Correct API usage
- Thread safety
- Initialization order
- Enable Library Debug Symbols
In Podfile or SPM:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
end
end
end
- Report Issue
If library bug:
- Create minimal reproduction
- File GitHub issue
- Include crash log and steps
Tools & Commands
Console.app Usage
Launch:
open -a Console
Filter by App:
- Click "Crash Reports" in sidebar
- Enter app name in search
- Select crash to view
Export: Right-click crash → "Reveal in Finder" → Copy file
atos for Symbolication
Basic Usage:
atos -arch arm64 \
-o /path/to/App.app.dSYM/Contents/Resources/DWARF/App \
-l 0x100000000 \
0x100001234
Parameters:
-arch: Architecture (arm64, x86_64)-o: Path to dSYM or binary-l: Load address from crash log- Last argument: Address to symbolicate
Multiple Addresses:
atos -arch arm64 -o MyApp.dSYM -l 0x100000000 \
0x100001234 0x100002345 0x100003456
Xcode Organizer
Access: Xcode → Window → Organizer
Features:
- View archives
- Download dSYMs for App Store builds
- View crash reports from TestFlight/App Store
- Automatic symbolication
Crashes Tab:
- Aggregate crashes from users
- Group by crash signature
- Filter by OS version, device
lldb Debugging
Set Breakpoint:
(lldb) breakpoint set --name ViewController.loginButtonTapped
(lldb) breakpoint set --file ViewController.swift --line 45
Examine Variables:
(lldb) po user
(lldb) p user?.name
(lldb) frame variable
Navigate Stack:
(lldb) bt # Print backtrace
(lldb) frame select 2 # Switch to frame 2
(lldb) up # Move up stack
(lldb) down # Move down stack
Memory Inspection:
(lldb) memory read 0x100001234
(lldb) register read
Integration with Simulator Workflows
Reproduce Crash in Simulator
Workflow:
1. Build app (xcode-workflows)
2. Boot simulator (simulator-workflows → boot)
3. Install app (simulator-workflows → install)
4. Launch with lldb attached (Xcode → Debug)
5. Reproduce crash
6. Analyze in debugger
Retrieve Logs:
1. Crash occurs in simulator
2. Console.app → Filter by app name
3. Or: ls ~/Library/Logs/DiagnosticReports/ | grep MyApp
4. Read crash log
5. Symbolicate if needed
Related Skills
- simulator-workflows: App lifecycle and device management
- xcode-workflows: Building with debug symbols
- ios-testing-patterns: Preventing crashes through testing
Related Resources
xc://reference/crash-types: Complete crash type referencexc://workflows/symbolication: Detailed symbolication guidexc://tools/debugging: LLDB and debugging tools reference
Tip: Enable Address Sanitizer and Undefined Behavior Sanitizer in scheme diagnostics to catch memory issues early.