Project 5: LLDB Python Scripting
Create a custom LLDB command in Python that summarizes the current frame.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Advanced |
| Time Estimate | 1 week |
| Language | Python (LLDB scripting), C (debug target) |
| Prerequisites | Projects 1-4, Python basics |
| Key Topics | LLDB Python API, custom commands, SBDebugger |
1. Learning Objectives
By completing this project, you will:
- Write a Python module that LLDB can import.
- Add a custom LLDB command via
command script add. - Access the target, process, thread, and frame from Python.
- Produce structured output about the current frame.
2. Theoretical Foundation
2.1 Core Concepts
- LLDB Python API: Exposes objects like
SBDebugger,SBTarget,SBProcess, andSBFrame. - Command Scripts: LLDB can register Python functions as first-class commands.
- Initialization:
~/.lldbinitcan auto-load Python scripts.
2.2 Why This Matters
Manual debugging does not scale. Python scripting lets you automate repetitive checks and build domain-specific commands, boosting productivity and consistency.
2.3 Historical Context / Background
LLDB was designed with scripting in mind. Its object model is exposed directly to Python, making it easier to extend than many legacy debuggers.
2.4 Common Misconceptions
- “Scripting is only for advanced users”: Even a small command can save hours.
- “I need a plugin system”: LLDB scripts are already a plugin system.
3. Project Specification
3.1 What You Will Build
A Python script that adds a frame_summary command to LLDB. When run, it prints the current function, file, line, and local variables.
3.2 Functional Requirements
- Custom command:
frame_summaryavailable in LLDB. - Frame inspection: Reads function name, file path, line number.
- Local variable listing: Prints names and values.
3.3 Non-Functional Requirements
- Reliability: Command should handle missing targets gracefully.
- Usability: Output should be concise and consistent.
3.4 Example Usage / Output
(lldb) command script import myscripts.py
Custom command 'frame_summary' loaded.
(lldb) b main
(lldb) run
(lldb) frame_summary
You are in function 'main'
at /path/to/my_program.c:10
Local variables:
- i: 0
3.5 Real World Outcome
You will type a single command in LLDB and see a structured summary of the current frame. Example output:
(lldb) frame_summary
You are in function 'main'
at /path/to/my_program.c:10
Local variables:
- i: 0
4. Solution Architecture
4.1 High-Level Design
LLDB -> Python import -> Register command -> Access frame -> Print summary
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
myscripts.py |
Provide frame_summary command |
Keep output short and readable |
__lldb_init_module |
Register command | Use command script add |
SBFrame access |
Read locals and line info | Validate objects before use |
4.3 Data Structures
# LLDB API objects accessed in order
SBDebugger -> SBTarget -> SBProcess -> SBThread -> SBFrame
4.4 Algorithm Overview
Key Algorithm: Frame Summary Command
- Get the selected target.
- Get the selected process/thread/frame.
- Extract function name, file, line.
- Iterate locals and print values.
Complexity Analysis:
- Time: O(n) over local variables
- Space: O(1)
5. Implementation Guide
5.1 Development Environment Setup
python3 --version
lldb --version
5.2 Project Structure
project-root/
├── my_program.c
├── myscripts.py
└── README.md
5.3 The Core Question You’re Answering
“How can I automate and standardize my debugging workflow inside LLDB?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- LLDB Object Model
- What does each SB* object represent?
- How do you navigate from debugger to frame?
- Command Registration
- How does
command script addwork? - What is the
__lldb_init_modulehook?
- How does
- Python Output Handling
- How does
resultcollect output?
- How does
5.5 Questions to Guide Your Design
Before implementing, think through these:
- What should the command print if no target is selected?
- How will you handle optimized-out locals?
- Should the output be a single block or line-by-line?
5.6 Thinking Exercise
Draft the Output Format
Sketch a template for your output (function, file, line, locals). Then compare with LLDB’s built-in frame info and decide how your command adds value.
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “How does LLDB’s Python API fit into the debugger architecture?”
- “What is
__lldb_init_moduleused for?” - “How would you add a custom command in LLDB?”
5.8 Hints in Layers
Hint 1: Start with basic validation
if not target:
result.SetError("Invalid target")
return
Hint 2: Use the selected frame
frame = target.GetProcess().GetSelectedThread().GetSelectedFrame()
Hint 3: Use result.AppendMessage for output
result.AppendMessage("Local variables:")
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Debugging automation | “The Art of Debugging with GDB” | Ch. 9 |
| LLDB scripting | “Advanced Apple Debugging & Reverse Engineering” | Ch. 5 |
| Python tooling | “Effective Python” | Ch. 1-3 |
5.10 Implementation Phases
Phase 1: Foundation (1 day)
Goals:
- Write the basic command and register it.
Tasks:
- Create
myscripts.pywith a stub command. - Register with
command script add. - Verify command exists with
help frame_summary.
Checkpoint: LLDB recognizes the command name.
Phase 2: Core Functionality (2-3 days)
Goals:
- Print function, file, and line.
- List local variables.
Tasks:
- Access
SBFrameandSBLineEntry. - Iterate locals and print name/value pairs.
Checkpoint: Output matches a real frame context.
Phase 3: Polish & Edge Cases (2-3 days)
Goals:
- Handle missing targets/frames.
- Improve output formatting.
Tasks:
- Add error handling for invalid states.
- Skip or label optimized-out locals.
Checkpoint: Command works even when stopped in system frames.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Output format | Single-line vs multi-line | Multi-line | Easier to scan |
| Load method | Manual import vs ~/.lldbinit |
Manual first | Debug the script easily |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Command Registration | Ensure command loads | command script import |
| Frame Access | Validate frame data | frame_summary |
| Edge Cases | No target/frame | Run in empty LLDB session |
6.2 Critical Test Cases
- Command loads: LLDB prints “Custom command loaded”.
- Frame summary works: Output shows function and line.
- Error handling: Command prints error when no target selected.
6.3 Test Data
Function: main
Line: 10
Locals: i=0
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Using wrong API methods | Attribute errors | Check help(lldb.SBFrame) |
| No selected target | Command fails | Validate target/process/frame |
| Optimized-out locals | Missing values | Compile with -O0 -g |
7.2 Debugging Strategies
- Print object validity:
frame.IsValid()before use. - Use LLDB Python REPL:
scriptcommand for quick experiments.
7.3 Performance Traps
Iterating large local lists can slow output; keep it concise.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add register values to the summary.
- Print arguments separately from locals.
8.2 Intermediate Extensions
- Add optional flags (e.g.,
frame_summary --verbose). - Detect and highlight optimized-out variables.
8.3 Advanced Extensions
- Cache and diff variables between stops.
- Integrate with stop hooks so it auto-runs on every stop.
9. Real-World Connections
9.1 Industry Applications
- Crash triage tooling: auto-collect frame summaries for reports.
- Debugging frameworks: internal LLDB extensions for large teams.
9.2 Related Open Source Projects
- LLDB Python API Docs: https://lldb.llvm.org/python_api/index.html
- LLDB: https://lldb.llvm.org
9.3 Interview Relevance
- Understanding debugger scripting shows advanced tooling knowledge.
10. Resources
10.1 Essential Reading
- LLDB Python Reference - https://lldb.llvm.org/use/python-reference.html
- Advanced Apple Debugging & Reverse Engineering by Derek Selander - Ch. 5
10.2 Video Resources
- LLDB scripting demos - LLDB community videos
10.3 Tools & Documentation
command script add: https://lldb.llvm.org/use/command.html#command
10.4 Related Projects in This Series
- Custom Data Formatter: extend LLDB to print complex types.
11. Self-Assessment Checklist
11.1 Understanding
- I can navigate the SB* object chain.
- I can explain how LLDB loads Python scripts.
- I can describe how my command interacts with the current frame.
11.2 Implementation
- My command loads and runs reliably.
- It prints function, file, and line correctly.
- It handles invalid targets gracefully.
11.3 Growth
- I can design a second custom command for my workflow.
- I can integrate the script into
~/.lldbinit.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Write and register a working
frame_summarycommand. - Output function and line information.
Full Completion:
- Include locals and arguments in the output.
- Handle missing target/process/frame gracefully.
Excellence (Going Above & Beyond):
- Add options or flags to the command.
- Auto-run the command on every stop via a stop hook.
This guide was generated from LEARN_LLDB_DEEP_DIVE.md. For the complete learning path, see the parent directory.