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:

  1. Write a Python module that LLDB can import.
  2. Add a custom LLDB command via command script add.
  3. Access the target, process, thread, and frame from Python.
  4. Produce structured output about the current frame.

2. Theoretical Foundation

2.1 Core Concepts

  • LLDB Python API: Exposes objects like SBDebugger, SBTarget, SBProcess, and SBFrame.
  • Command Scripts: LLDB can register Python functions as first-class commands.
  • Initialization: ~/.lldbinit can 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

  1. Custom command: frame_summary available in LLDB.
  2. Frame inspection: Reads function name, file path, line number.
  3. 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

  1. Get the selected target.
  2. Get the selected process/thread/frame.
  3. Extract function name, file, line.
  4. 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:

  1. LLDB Object Model
    • What does each SB* object represent?
    • How do you navigate from debugger to frame?
  2. Command Registration
    • How does command script add work?
    • What is the __lldb_init_module hook?
  3. Python Output Handling
    • How does result collect output?

5.5 Questions to Guide Your Design

Before implementing, think through these:

  1. What should the command print if no target is selected?
  2. How will you handle optimized-out locals?
  3. 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:

  1. “How does LLDB’s Python API fit into the debugger architecture?”
  2. “What is __lldb_init_module used for?”
  3. “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:

  1. Create myscripts.py with a stub command.
  2. Register with command script add.
  3. 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:

  1. Access SBFrame and SBLineEntry.
  2. 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:

  1. Add error handling for invalid states.
  2. 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

  1. Command loads: LLDB prints “Custom command loaded”.
  2. Frame summary works: Output shows function and line.
  3. 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: script command 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.
  • 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

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_summary command.
  • 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.