Add scan flow MVP and local Axiom skill workspace
This snapshot establishes the camera-to-result recognition flow and related tests while checking in the project skill/docs assets required for the configured local tooling.
This commit is contained in:
480
.claude/skills/axiom-lldb-ref/SKILL.md
Normal file
480
.claude/skills/axiom-lldb-ref/SKILL.md
Normal file
@@ -0,0 +1,480 @@
|
||||
---
|
||||
name: axiom-lldb-ref
|
||||
description: Complete LLDB command reference — variable inspection, breakpoints, threads, expression evaluation, process control, memory commands, and .lldbinit customization
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# LLDB Command Reference
|
||||
|
||||
Complete command reference for LLDB in Xcode. Organized by task so you can find the exact command you need.
|
||||
|
||||
For debugging workflows and decision trees, see `/skill axiom-lldb`.
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Variable Inspection
|
||||
|
||||
### `v` / `frame variable`
|
||||
|
||||
Reads memory directly. No compilation. Most reliable for Swift values.
|
||||
|
||||
```
|
||||
(lldb) v # All variables in current frame
|
||||
(lldb) v self # Self in current context
|
||||
(lldb) v self.propertyName # Specific property
|
||||
(lldb) v localVariable # Local variable
|
||||
(lldb) v self.array[0] # Collection element
|
||||
(lldb) v self._showDetails # SwiftUI @State backing store (underscore prefix)
|
||||
```
|
||||
|
||||
**Flags:**
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-d run` | Run dynamic type resolution (slower but more accurate) |
|
||||
| `-T` | Show types |
|
||||
| `-R` | Show raw (unformatted) output |
|
||||
| `-D N` | Limit depth of nested types to N levels |
|
||||
| `-P N` | Limit pointer depth to N levels |
|
||||
| `-F` | Flat output (no hierarchy) |
|
||||
|
||||
**Limitations:** Cannot evaluate expressions, computed properties, or function calls. Use `p` for those.
|
||||
|
||||
### `p` / `expression` (with format)
|
||||
|
||||
Compiles and executes an expression. Shows formatted result.
|
||||
|
||||
```
|
||||
(lldb) p self.computedProperty
|
||||
(lldb) p items.count
|
||||
(lldb) p someFunction()
|
||||
(lldb) p String(describing: someValue)
|
||||
(lldb) p (1...10).map { $0 * 2 }
|
||||
```
|
||||
|
||||
Result stored in numbered variables:
|
||||
|
||||
```
|
||||
(lldb) p someValue
|
||||
$R0 = 42
|
||||
(lldb) p $R0 + 10
|
||||
$R1 = 52
|
||||
```
|
||||
|
||||
### `po` / `expression --object-description`
|
||||
|
||||
Calls `debugDescription` (or `description`) on the result.
|
||||
|
||||
```
|
||||
(lldb) po myObject
|
||||
(lldb) po error
|
||||
(lldb) po notification.userInfo
|
||||
(lldb) po NSHomeDirectory()
|
||||
```
|
||||
|
||||
**When `po` adds value:** Classes with `CustomDebugStringConvertible`, `NSError`, `NSNotification`, collections of objects.
|
||||
|
||||
**When `po` fails:** Swift structs without `CustomDebugStringConvertible`, protocol-typed values (use `v` instead — it performs iterative dynamic type resolution that `po` doesn't).
|
||||
|
||||
### `expression` (full form)
|
||||
|
||||
Full expression evaluation with all options.
|
||||
|
||||
```
|
||||
(lldb) expression self.view.backgroundColor = UIColor.red
|
||||
(lldb) expression self.debugFlag = true
|
||||
(lldb) expression myArray.append("test")
|
||||
(lldb) expression CATransaction.flush() # Force UI update
|
||||
(lldb) expression Self._printChanges() # SwiftUI debug
|
||||
```
|
||||
|
||||
**Flags:**
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-l objc` | Evaluate as Objective-C |
|
||||
| `-l swift` | Evaluate as Swift (default) |
|
||||
| `-O` | Object description (same as `po`) |
|
||||
| `-i false` | Stop on breakpoints hit during evaluation (default: ignore) |
|
||||
| `--` | Separator between flags and expression |
|
||||
|
||||
**ObjC expressions for Swift debugging:**
|
||||
|
||||
```
|
||||
(lldb) expr -l objc -- (void)[[[UIApplication sharedApplication] keyWindow] recursiveDescription]
|
||||
(lldb) expr -l objc -- (void)[CATransaction flush]
|
||||
(lldb) expr -l objc -- (int)[[UIApplication sharedApplication] _isForeground]
|
||||
```
|
||||
|
||||
### `register read`
|
||||
|
||||
Low-level register inspection:
|
||||
|
||||
```
|
||||
(lldb) register read
|
||||
(lldb) register read x0 x1 # Specific registers (ARM64)
|
||||
(lldb) register read --all # All register sets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 2: Breakpoints
|
||||
|
||||
### Setting Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -f File.swift -l 42 # File + line
|
||||
(lldb) b File.swift:42 # Short form
|
||||
(lldb) breakpoint set -n methodName # By function name
|
||||
(lldb) breakpoint set -n "MyClass.myMethod" # Qualified name
|
||||
(lldb) breakpoint set -S layoutSubviews # ObjC selector
|
||||
(lldb) breakpoint set -r "viewDid.*" # Regex on name
|
||||
(lldb) breakpoint set -a 0x100abc123 # Memory address
|
||||
```
|
||||
|
||||
### Conditional Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -f File.swift -l 42 -c "value == nil"
|
||||
(lldb) breakpoint set -f File.swift -l 42 -c "index > 100"
|
||||
(lldb) breakpoint set -f File.swift -l 42 -c 'name == "test"'
|
||||
```
|
||||
|
||||
### Ignore Count
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -f File.swift -l 42 -i 50 # Skip first 50 hits
|
||||
```
|
||||
|
||||
### One-Shot Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -f File.swift -l 42 -o # Delete after first hit
|
||||
```
|
||||
|
||||
### Breakpoint Commands (Logpoints)
|
||||
|
||||
Add commands that execute when breakpoint hits:
|
||||
|
||||
```
|
||||
(lldb) breakpoint command add 1
|
||||
> v self.state
|
||||
> p self.items.count
|
||||
> continue
|
||||
> DONE
|
||||
```
|
||||
|
||||
Or in one line:
|
||||
|
||||
```
|
||||
(lldb) breakpoint command add 1 -o "v self.state"
|
||||
```
|
||||
|
||||
### Exception Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -E swift # All Swift errors
|
||||
(lldb) breakpoint set -E objc # All ObjC exceptions
|
||||
# Filtering by exception name requires Xcode's GUI (Edit Breakpoint → Exception field)
|
||||
```
|
||||
|
||||
### Symbolic Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint set -n UIViewAlertForUnsatisfiableConstraints # Auto Layout
|
||||
(lldb) breakpoint set -n "-[UIApplication _run]" # App launch
|
||||
(lldb) breakpoint set -n swift_willThrow # Swift throw
|
||||
```
|
||||
|
||||
### Managing Breakpoints
|
||||
|
||||
```
|
||||
(lldb) breakpoint list # List all
|
||||
(lldb) breakpoint list -b # Brief format
|
||||
(lldb) breakpoint enable 3 # Enable breakpoint 3
|
||||
(lldb) breakpoint disable 3 # Disable breakpoint 3
|
||||
(lldb) breakpoint delete 3 # Delete breakpoint 3
|
||||
(lldb) breakpoint delete # Delete ALL (asks confirmation)
|
||||
(lldb) breakpoint modify 3 -c "x > 10" # Add condition to existing
|
||||
```
|
||||
|
||||
### Watchpoints
|
||||
|
||||
Break when a variable's memory changes:
|
||||
|
||||
```
|
||||
(lldb) watchpoint set variable self.count # Watch for write
|
||||
(lldb) watchpoint set variable -w read_write myGlobal # Watch for read or write
|
||||
(lldb) watchpoint set expression -- &myVariable # Watch memory address
|
||||
(lldb) watchpoint list # List all
|
||||
(lldb) watchpoint delete 1 # Delete watchpoint 1
|
||||
(lldb) watchpoint modify 1 -c "self.count > 10" # Add condition
|
||||
```
|
||||
|
||||
**Note:** Hardware watchpoints are limited (~4 per process). Use sparingly.
|
||||
|
||||
---
|
||||
|
||||
## Part 3: Thread & Backtrace
|
||||
|
||||
### Backtraces
|
||||
|
||||
```
|
||||
(lldb) bt # Current thread backtrace
|
||||
(lldb) bt 10 # Limit to 10 frames
|
||||
(lldb) bt all # All threads
|
||||
(lldb) thread backtrace all # Same as bt all
|
||||
```
|
||||
|
||||
### Thread Navigation
|
||||
|
||||
```
|
||||
(lldb) thread list # List all threads with state
|
||||
(lldb) thread info # Current thread details + stop reason
|
||||
(lldb) thread select 3 # Switch to thread 3
|
||||
```
|
||||
|
||||
### Frame Navigation
|
||||
|
||||
```
|
||||
(lldb) frame info # Current frame details
|
||||
(lldb) frame select 5 # Jump to frame 5
|
||||
(lldb) up # Go up one frame (toward caller)
|
||||
(lldb) down # Shortcut: go down one frame
|
||||
```
|
||||
|
||||
### Thread Return (Skip Code)
|
||||
|
||||
Force an early return from the current function:
|
||||
|
||||
```
|
||||
(lldb) thread return # Return void
|
||||
(lldb) thread return 42 # Return specific value
|
||||
```
|
||||
|
||||
**Use with caution** — skips cleanup code, can leave state inconsistent.
|
||||
|
||||
---
|
||||
|
||||
## Part 4: Expression Evaluation
|
||||
|
||||
### Swift Expressions
|
||||
|
||||
```
|
||||
(lldb) expr let x = 42; print(x)
|
||||
(lldb) expr self.view.backgroundColor = UIColor.red
|
||||
(lldb) expr UIApplication.shared.windows.first?.rootViewController
|
||||
(lldb) expr UserDefaults.standard.set(true, forKey: "debug")
|
||||
```
|
||||
|
||||
### Objective-C Expressions
|
||||
|
||||
Switch to ObjC when Swift expression parser fails:
|
||||
|
||||
```
|
||||
(lldb) expr -l objc -- (void)[CATransaction flush]
|
||||
(lldb) expr -l objc -- (id)[[UIApplication sharedApplication] keyWindow]
|
||||
(lldb) expr -l objc -- (void)[[NSNotificationCenter defaultCenter] postNotificationName:@"test" object:nil]
|
||||
```
|
||||
|
||||
### UI Debugging Expressions
|
||||
|
||||
```
|
||||
(lldb) expr -l objc -- (void)[[[UIApplication sharedApplication] keyWindow] recursiveDescription]
|
||||
(lldb) po UIApplication.shared.windows.first?.rootViewController?.view.recursiveDescription()
|
||||
```
|
||||
|
||||
### SwiftUI Debugging
|
||||
|
||||
```
|
||||
(lldb) expr Self._printChanges() # Print what triggered body re-eval (inside view body only)
|
||||
```
|
||||
|
||||
### Runtime Type Information
|
||||
|
||||
```
|
||||
(lldb) expr type(of: someValue)
|
||||
(lldb) expr String(describing: type(of: someValue))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 5: Process Control
|
||||
|
||||
### Execution Control
|
||||
|
||||
```
|
||||
(lldb) continue # Resume execution (c)
|
||||
(lldb) c # Short form
|
||||
(lldb) process interrupt # Pause running process
|
||||
(lldb) thread step-over # Step over (n / next)
|
||||
(lldb) n # Short form
|
||||
(lldb) thread step-in # Step into (s / step)
|
||||
(lldb) s # Short form
|
||||
(lldb) thread step-out # Step out (finish)
|
||||
(lldb) finish # Short form
|
||||
(lldb) thread step-inst # Step one instruction (assembly-level)
|
||||
(lldb) ni # Step over one instruction
|
||||
```
|
||||
|
||||
### Process Management
|
||||
|
||||
```
|
||||
(lldb) process launch # Launch/restart
|
||||
(lldb) process attach --pid 1234 # Attach to running process
|
||||
(lldb) process attach --name MyApp # Attach by name
|
||||
(lldb) process detach # Detach without killing
|
||||
(lldb) kill # Kill debugged process
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 6: Memory & Image
|
||||
|
||||
### Memory Reading
|
||||
|
||||
```
|
||||
(lldb) memory read 0x100abc123 # Read memory at address
|
||||
(lldb) memory read -c 64 0x100abc123 # Read 64 bytes
|
||||
(lldb) memory read -f x 0x100abc123 # Format as hex
|
||||
(lldb) memory read -f s 0x100abc123 # Format as string
|
||||
```
|
||||
|
||||
### Memory Search
|
||||
|
||||
```
|
||||
(lldb) memory find -s "searchString" -- 0x100000000 0x200000000
|
||||
```
|
||||
|
||||
### Image/Module Inspection
|
||||
|
||||
```
|
||||
(lldb) image lookup -a 0x100abc123 # Lookup symbol at address
|
||||
(lldb) image lookup -n myFunction # Find function by name
|
||||
(lldb) image lookup -rn "MyClass.*" # Regex search
|
||||
(lldb) image list # List all loaded images/frameworks
|
||||
(lldb) image list -b # Brief format
|
||||
```
|
||||
|
||||
**Common use:** Finding which framework a crash address belongs to:
|
||||
|
||||
```
|
||||
(lldb) image lookup -a 0x1a2b3c4d5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 7: .lldbinit & Customization
|
||||
|
||||
### File Location
|
||||
|
||||
LLDB reads `~/.lldbinit` at startup. Per-project init files are also supported when configured in Xcode's scheme settings.
|
||||
|
||||
### Useful Aliases
|
||||
|
||||
Add to `~/.lldbinit`:
|
||||
|
||||
```
|
||||
# Quick reload — flush UI changes made via expression
|
||||
command alias flush expr -l objc -- (void)[CATransaction flush]
|
||||
|
||||
# Print view hierarchy
|
||||
command alias views expr -l objc -- (void)[[[UIApplication sharedApplication] keyWindow] recursiveDescription]
|
||||
|
||||
# Print auto layout constraints
|
||||
command alias constraints po [[UIWindow keyWindow] _autolayoutTrace]
|
||||
```
|
||||
|
||||
### Custom Type Summaries
|
||||
|
||||
```
|
||||
# Show CLLocationCoordinate2D as "lat, lon"
|
||||
type summary add CLLocationCoordinate2D --summary-string "${var.latitude}, ${var.longitude}"
|
||||
```
|
||||
|
||||
### Settings
|
||||
|
||||
```
|
||||
(lldb) settings show target.language # Current language
|
||||
(lldb) settings set target.language swift # Force Swift mode
|
||||
(lldb) settings set target.max-children-count 100 # Show more collection items
|
||||
```
|
||||
|
||||
### Per-Project .lldbinit
|
||||
|
||||
In Xcode: Edit Scheme → Run → Options → "LLDB Init File" field.
|
||||
|
||||
Put project-specific aliases and breakpoints in a `.lldbinit` file in your project root.
|
||||
|
||||
---
|
||||
|
||||
## Part 8: Troubleshooting LLDB Itself
|
||||
|
||||
### "expression failed to parse"
|
||||
|
||||
**Cause:** Swift expression parser can't resolve types from the current module.
|
||||
|
||||
**Fixes:**
|
||||
1. Use `v` instead (no compilation needed)
|
||||
2. Simplify the expression
|
||||
3. Try `expr -l objc -- ...` for ObjC-bridge types
|
||||
4. Clean derived data and rebuild
|
||||
|
||||
### "variable not available"
|
||||
|
||||
**Cause:** Compiler optimized the variable out.
|
||||
|
||||
**Fixes:**
|
||||
1. Switch to Debug build configuration
|
||||
2. Set `-Onone` for the specific file (Build Settings → per-file compiler flags)
|
||||
3. Use `register read` to check if the value is in a register
|
||||
|
||||
### "wrong language mode"
|
||||
|
||||
**Cause:** LLDB defaults to ObjC in some contexts (especially in frameworks).
|
||||
|
||||
**Fix:**
|
||||
```
|
||||
(lldb) settings set target.language swift
|
||||
(lldb) expr -l swift -- mySwiftExpression
|
||||
```
|
||||
|
||||
### "expression caused a crash"
|
||||
|
||||
**Cause:** The expression you evaluated had a side effect that crashed.
|
||||
|
||||
**Fix:**
|
||||
1. Don't evaluate expressions that modify state unless you intend to
|
||||
2. Use `v` for read-only inspection
|
||||
3. If the crash corrupted state, restart the debug session
|
||||
|
||||
### LLDB Hangs or Is Slow
|
||||
|
||||
**Cause:** Usually compiling a complex expression or resolving types in a large project.
|
||||
|
||||
**Fix:**
|
||||
1. Use `v` instead of `p`/`po` (no compilation)
|
||||
2. Reduce expression complexity
|
||||
3. If LLDB hangs during `po`, Ctrl+C to cancel and use `v` instead
|
||||
|
||||
### Breakpoint Not Hit
|
||||
|
||||
**Causes and fixes:**
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| Wrong file/line (code moved) | Re-set breakpoint on current code |
|
||||
| Breakpoint disabled | `breakpoint enable N` |
|
||||
| Code not executed | Verify the code path is reached |
|
||||
| Optimized out (Release) | Switch to Debug configuration |
|
||||
| In a framework/SPM package | Set symbolic breakpoint by function name |
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
**WWDC**: 2019-429, 2018-412, 2022-110370, 2015-402
|
||||
|
||||
**Docs**: /xcode/stepping-through-code-and-inspecting-variables-to-isolate-bugs, /xcode/setting-breakpoints-to-pause-your-running-app
|
||||
|
||||
**Skills**: axiom-lldb, axiom-xcode-debugging
|
||||
Reference in New Issue
Block a user