Project 2: System Call Monitor (Your First C BPF Program)
A complete BPF program in C that monitors system calls, counts them by type and process, and displays real-time statistics—essentially your own version of
stracebut with kernel-level efficiency.
Quick Reference
| Attribute | Value |
|---|---|
| Primary Language | C (libbpf) |
| Alternative Languages | Go (cilium/ebpf), Rust (aya) |
| Difficulty | Level 2: Intermediate |
| Time Estimate | 1-2 weeks |
| Knowledge Area | BPF Programming / System Calls |
| Tooling | libbpf, clang, bpftool |
| Prerequisites | C programming, Project 1 completed, basic understanding of Linux syscalls |
What You Will Build
A complete BPF program in C that monitors system calls, counts them by type and process, and displays real-time statistics—essentially your own version of strace but with kernel-level efficiency.
Why It Matters
This forces you to understand the complete BPF development workflow: writing BPF C code, compiling with clang, loading with libbpf, and communicating between kernel and userspace via maps.
Core Challenges
- Setting up the BPF development environment → maps to clang, libbpf, kernel headers
- Writing BPF-compatible C code → maps to verifier constraints, helper functions
- Defining and using BPF maps → maps to data sharing between kernel and userspace
- Loading and attaching programs → maps to libbpf skeleton, bpf() syscall
Key Concepts
- BPF Program Structure: “Learning eBPF” Chapter 3 - Liz Rice
- BPF Maps: “Learning eBPF” Chapter 4 - Liz Rice
- libbpf-bootstrap: GitHub libbpf-bootstrap
- CO-RE and BTF: Andrii Nakryiko’s Blog on CO-RE
Real-World Outcome
$ sudo ./syscall_monitor
PID COMM SYSCALL COUNT RATE/s
1234 nginx read 15234 1523.4
1234 nginx write 12892 1289.2
1234 nginx epoll_wait 8923 892.3
5678 postgres read 45123 4512.3
5678 postgres futex 23891 2389.1
9012 chrome mmap 3421 342.1
9012 chrome munmap 2198 219.8
[Top syscalls last 10 seconds]
read: 123,456 (45.2%)
write: 89,123 (32.7%)
epoll_wait: 34,567 (12.7%)
futex: 15,234 (5.6%)
mmap: 10,234 (3.8%)
Implementation Guide
- Reproduce the simplest happy-path scenario.
- Build the smallest working version of the core feature.
- Add input validation and error handling.
- Add instrumentation/logging to confirm behavior.
- Refactor into clean modules with tests.
Milestones
- Milestone 1: Minimal working program that runs end-to-end.
- Milestone 2: Correct outputs for typical inputs.
- Milestone 3: Robust handling of edge cases.
- Milestone 4: Clean structure and documented usage.
Validation Checklist
- Output matches the real-world outcome example
- Handles invalid inputs safely
- Provides clear errors and exit codes
- Repeatable results across runs
References
- Main guide:
LEARN_BPF_EBPF_LINUX.md - “Learning eBPF” by Liz Rice