Project 1: The Basics - First Steps
Build a tiny C program and learn the LLDB loop: break, step, inspect, repeat.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Beginner |
| Time Estimate | 1-2 hours |
| Language | C (debug target), LLDB commands |
| Prerequisites | Basic C syntax, compiling with -g |
| Key Topics | Breakpoints, stepping, stack frames, variable inspection |
1. Learning Objectives
By completing this project, you will:
- Set and manage breakpoints in LLDB.
- Step through code while tracking control flow.
- Inspect variables, arguments, and stack frames.
- Understand the LLDB object model at a basic level (target/process/thread/frame).
2. Theoretical Foundation
2.1 Core Concepts
- Debug Symbols (DWARF): Debug info maps source lines and variables to addresses and registers. Without
-g, LLDB can only show assembly and raw addresses. - Breakpoints vs. Stepping: Breakpoints choose where execution stops; stepping controls how you move between statements.
- Stack Frames: Each function call pushes a frame containing arguments, locals, and a return address.
btandframecommands are views into this stack.
2.2 Why This Matters
This workflow is the base layer for every later debugging task. If you cannot reliably stop at a point of interest, inspect state, and reason about the call stack, you will not be able to diagnose crashes, hangs, or data corruption effectively.
2.3 Historical Context / Background
LLDB was built as part of the LLVM project to be fast, scriptable, and Clang-aware. The command set differs from GDB, but the mental model is identical: load a target, start a process, select a thread, inspect a frame.
2.4 Common Misconceptions
- “Step” means the next line: It really means the next instruction that belongs to the current frame; function calls change the frame.
- Breakpoints are only for lines: You can break on functions, symbols, addresses, or conditions.
3. Project Specification
3.1 What You Will Build
A minimal C program with a loop and a helper function, compiled with debug symbols. The learning deliverable is a repeatable LLDB session that stops at main, steps into greet, and inspects i and count.
3.2 Functional Requirements
- Compile with symbols: Produce a binary with
-g. - Set a breakpoint: Break at
mainor a specific line. - Step and inspect: Use
next,step,frame variable, andbt.
3.3 Non-Functional Requirements
- Performance: Not relevant; keep the program tiny.
- Reliability: Deterministic behavior so LLDB output is consistent.
- Usability: Your LLDB command history should be repeatable.
3.4 Example Usage / Output
$ clang -g -o target target.c
$ lldb ./target
(lldb) b main
(lldb) run
Process 12345 stopped
* thread #1, stop reason = breakpoint 1.1
frame #0: 0x0000000100003f7a target`main at target.c:9
(lldb) n
(lldb) fr v i
(int) i = 0
(lldb) s
(lldb) bt
3.5 Real World Outcome
You will see LLDB pause at your breakpoint and display the current source line. The debugger will show the call stack and print the current value of i. For example, after stepping once:
$ lldb ./target
(lldb) b main
(lldb) run
Process 12345 stopped
* thread #1, stop reason = breakpoint 1.1
frame #0: 0x0000000100003f7a target`main at target.c:9
(lldb) fr v i
(int) i = 0
4. Solution Architecture
4.1 High-Level Design
Source (.c) -> Compile with -g -> Binary + DWARF
-> LLDB target -> Process -> Thread -> Frame
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
target.c |
Simple loop + function | Keep control flow easy to follow |
| LLDB session | Breakpoint, stepping, inspection | Use function breakpoints for clarity |
4.3 Data Structures
// Minimal program state for inspection
void greet(int count) {
printf("Hello for the %dth time!\n", count);
}
4.4 Algorithm Overview
Key Algorithm: Step/Inspect Loop
- Break at
main. - Step over loop setup.
- Inspect variable
i. - Step into
greet. - Observe new frame on stack.
Complexity Analysis:
- Time: O(n) for loop iterations
- Space: O(1)
5. Implementation Guide
5.1 Development Environment Setup
clang --version
lldb --version
5.2 Project Structure
project-root/
├── target.c
└── README.md
5.3 The Core Question You’re Answering
“How does a debugger map source code to running machine instructions, and how do I navigate that mapping?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Debug Symbols (
-g)- What does DWARF store?
- Why does stripping symbols break source-level debugging?
- Book Reference: “Linkers and Loaders” Ch. 1-2
- Stack Frames
- What is a call frame, and what lives inside it?
- How does
btrelate to the frame chain? - Book Reference: CS:APP Ch. 3.7
- Breakpoints vs. Watchpoints
- What triggers each type of stop?
- When should you use a breakpoint only?
5.5 Questions to Guide Your Design
Before implementing, think through these:
- Where should you place a breakpoint to see the loop initialize?
- How can you verify you are inside
greetwithout reading source? - What do you expect
btto show before and after stepping intogreet?
5.6 Thinking Exercise
Trace the Call Stack
Draw the stack as you step into greet. Which frame is on top? Which frame is below it? How does the call stack change when you return?
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “What is the difference between
nextandstepin LLDB?” - “Why does
btsometimes show functions you did not call explicitly?” - “What do debug symbols do, and how do they get into the binary?”
5.8 Hints in Layers
Hint 1: Use function breakpoints
(lldb) b greet
Hint 2: Print locals quickly
(lldb) fr v
Hint 3: Use bt after step
You should see greet on the top frame.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Debug symbols | “Linkers and Loaders” | Ch. 1-2 |
| Stack frames | “Computer Systems: A Programmer’s Perspective” | Ch. 3.7 |
| Debugging fundamentals | “The Art of Debugging with GDB” | Ch. 1-3 |
5.10 Implementation Phases
Phase 1: Foundation (20 minutes)
Goals:
- Compile with debug symbols.
- Launch LLDB and load the binary.
Tasks:
- Write
target.c. - Compile with
clang -g. - Start
lldb ./targetand set a breakpoint.
Checkpoint: LLDB stops at main and shows the correct source line.
Phase 2: Core Functionality (30 minutes)
Goals:
- Step over the loop.
- Inspect variables.
Tasks:
- Use
nextto move through the loop setup. - Inspect
iwithframe variable i.
Checkpoint: You can explain why i changes as you step.
Phase 3: Polish & Edge Cases (20 minutes)
Goals:
- Step into
greetand confirm the call stack.
Tasks:
- Use
stepon thegreet(i)line. - Use
btandframe select.
Checkpoint: You can select the correct frame and read locals.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Breakpoint location | main vs greet |
Start with main |
See full setup before function call |
| Stepping method | next vs step |
Use both | Compare frame behavior |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Manual Debugging | Validate LLDB commands | b main, n, s, fr v |
| Sanity Check | Ensure program output matches expectation | ./target prints 5 lines |
6.2 Critical Test Cases
- Breakpoint hits
main: LLDB stops at line containingmainbody. - Step into
greet:btshowsgreeton top frame. - Variable inspection:
iandcountshow correct values.
6.3 Test Data
Loop runs 5 iterations (0..4)
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
Forgot -g |
LLDB shows assembly only | Recompile with -g |
Confusing s/n |
Unexpected frame changes | Use help thread step-in |
| Optimizations on | Variables seem optimized away | Compile with -O0 -g |
7.2 Debugging Strategies
- Check symbol load:
image listandtarget modules list. - Verify line mapping:
listto confirm source lines.
7.3 Performance Traps
Not applicable for this project.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a second helper function and step through both.
- Use a conditional breakpoint:
b main -c 'i == 3'.
8.2 Intermediate Extensions
- Use
thread backtrace allto see all threads. - Compare stepping in optimized vs. unoptimized builds.
8.3 Advanced Extensions
- Use
disassemble --frameto connect source to assembly. - Write a short LLDB command script that sets your standard breakpoints.
9. Real-World Connections
9.1 Industry Applications
- Crash triage: Quickly stop, inspect, and report repro steps.
- Performance hot spots: Step through code to confirm expected path.
9.2 Related Open Source Projects
- LLDB: https://lldb.llvm.org - The debugger you are using.
- LLVM: https://llvm.org - Toolchain context for LLDB.
9.3 Interview Relevance
- Breakpoints, stepping, and call stacks are universal debugging topics.
10. Resources
10.1 Essential Reading
- The LLDB Tutorial - https://lldb.llvm.org/use/tutorial.html
- The Art of Debugging with GDB by Norman Matloff - Ch. 1-3
10.2 Video Resources
- LLDB basics walkthrough - LLDB YouTube channel
10.3 Tools & Documentation
- LLDB Command Reference: https://lldb.llvm.org/use/command.html
10.4 Related Projects in This Series
- The Crash - Crash Report Analysis: moves from live debugging to post-mortem analysis.
11. Self-Assessment Checklist
11.1 Understanding
- I can explain how LLDB uses DWARF symbols to map source lines.
- I can describe the target/process/thread/frame model.
- I can explain the difference between
nextandstep.
11.2 Implementation
- All breakpoints and steps behave as expected.
- I can inspect locals and the call stack.
- I can repeat the debugging session without notes.
11.3 Growth
- I can describe my debugging workflow in a job interview.
- I can teach a teammate the LLDB basics.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Compile with
-gand run LLDB. - Break at
mainand step intogreet. - Print
iand confirm the call stack.
Full Completion:
- Use a conditional breakpoint and explain why it works.
- Demonstrate stepping into and out of frames.
Excellence (Going Above & Beyond):
- Connect source lines to assembly using
disassemble. - Record your LLDB session commands as a reusable script.
This guide was generated from LEARN_LLDB_DEEP_DIVE.md. For the complete learning path, see the parent directory.