Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Description

<!-- What does this PR do? Which problem does it solve? -->

## Why this approach

<!-- Explain why you chose this approach over alternatives. -->

---

## Checklist

- [ ] Commit prefix matches changed area (e.g., `tools/toolname:`, `libbpf-tools/toolname:`, `src/cc:`, `doc:`, `build:`, `tests/python:`)
- [ ] Commit body explains **why** this change is needed

**For new tools only**
- [ ] Explains why this tool is needed and what existing tools cannot cover this use case
- [ ] Includes at least one real production use case
- [ ] Man page (`man/man8/`) with OVERHEAD and CAVEATS sections
- [ ] Example output file (`*_example.txt`)
- [ ] README.md entry added
- [ ] Smoke test added to `tests/python/test_tools_smoke.py`

---

> **Note:** The maintainer may request a Copilot code review on this PR.
> AI feedback is advisory only — reply with your reasoning if you disagree; the maintainer decides.
54 changes: 54 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# BCC Project — GitHub Copilot Instructions

BCC is a toolkit for creating efficient kernel tracing and manipulation programs using eBPF. Tools run in **mission-critical environments as root**.

## Global Review Principles (Applied to all PRs)

### Commit Message Format

```
<prefix>: <short summary>

<WHY this change is needed — not just what changed>
- Problem being solved
- Why this approach was chosen
```

**Prefixes:** `tools/toolname:`, `libbpf-tools/toolname:`, `src/cc:`, `build:`, `ci:`, `doc:`, `tests/python:`

### Style Checks

- **Python:** `scripts/py-style-check.sh` (pycodestyle, ignore E123/E125/E126/E127/E128/E302)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scripts/py-style-check.sh does more than run pycodestyle: it also fails on executable tools/ and examples/ Python files that don’t use the #!/usr/bin/python shebang. Consider mentioning that shebang/executable-bit check here so contributors aren’t surprised when style checks fail.

Suggested change
- **Python:** `scripts/py-style-check.sh` (pycodestyle, ignore E123/E125/E126/E127/E128/E302)
- **Python:** `scripts/py-style-check.sh` (runs `pycodestyle` ignoring E123/E125/E126/E127/E128/E302, and also fails on executable `tools/` and `examples/` Python files that don’t use the `#!/usr/bin/python` shebang)

Copilot uses AI. Check for mistakes.
- **C/C++:** `scripts/c-style-check.sh` (git clang-format against master)

<CriticalRules>
- MUST perform a NULL check after any BPF C Map lookup.
- MUST perform a NULL check after every `malloc()`, `calloc()`, `realloc()`, and `strdup()` call in userspace C code.
- MUST perform a bounds check for all array accesses.
- BPF C functions: flag if stack usage appears to approach or exceed 512 bytes (eBPF verifier hard limit).
- Default output format MUST be under 80 characters wide.
</CriticalRules>

### Documentation Requirements (New Tools)

All **new tools** require these **minimum** files (enforce as blocker):
1. Tool script
2. Man page (`man/man8/`) with **OVERHEAD** and **CAVEATS** sections
3. `README.md` entry

Additional per-subsystem requirements apply — defer to the relevant
`instructions/*.instructions.md` file (e.g., `tools.instructions.md` also
requires `tests/python/test_tools_smoke.py`; `*_example.txt` is required for
`tools/` but recommended for `libbpf-tools/`).

For **bug-fix or enhancement PRs on existing tools**: flag missing docs as 🟡 Warning, not a blocker.
> Note: ~14% of libbpf-tools currently ship without a man page — this is a known gap, not a reason to skip the requirement for new tools.

### Unix Philosophy

- Do one thing and do it well
- Default output **< 80 characters wide**
- Prefer short tool names; avoid underscores for new tools unless needed for
clarity or to match an existing naming pattern (e.g., `mysqld_qslower`)
- Prefer a positional argument for the most common parameter (e.g., interval) over a flag,
where it makes sense for the tool's use case
66 changes: 66 additions & 0 deletions .github/instructions/core.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
applyTo: "src/cc/**"
---

# BCC Core Library Review Instructions

All BCC tools depend on this code — stability and backward compatibility are critical.

<CriticalRules>
- MUST NOT break public C++ APIs without a deprecation cycle.
- When changing a C++ function signature, MUST update `src/python/bcc/__init__.py` ctypes bindings.
- MUST NULL-check every `malloc()`, `calloc()`, `realloc()`, and `strdup()` call.
Comment on lines +10 to +12
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/python/bcc/__init__.py doesn’t appear to be where the libbcc ctypes function signatures are defined; those argtypes/restype bindings live in src/python/bcc/libbcc.py (and __init__.py mostly wraps higher-level APIs). This rule should point to libbcc.py (and any wrapper call sites) so reviewers update the correct bindings when C/C++ signatures change.

Copilot uses AI. Check for mistakes.
- MUST use negative errno consistently for error returns.
- MUST guard all architecture-specific code with `#ifdef __x86_64__` / `#ifdef __aarch64__` etc.
</CriticalRules>

## API & ABI Stability

- Deprecate gracefully: add `[[deprecated(...)]]` and a one-time `fprintf(stderr, "Warning: …")` in the old function body
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deprecation guidance introduces [[deprecated(...)]] + a runtime fprintf warning, but the repo doesn’t currently use [[deprecated]] anywhere. Consider aligning with existing deprecation patterns (e.g., __attribute__((deprecated("...")))) or documenting that this is a new convention and ensuring it matches the project’s supported compilers/standards.

Suggested change
- Deprecate gracefully: add `[[deprecated(...)]]` and a one-time `fprintf(stderr, "Warning: …")` in the old function body
- Deprecate gracefully: use the project’s existing deprecation attribute (for example, `__attribute__((deprecated("…")))`) and a one-time `fprintf(stderr, "Warning: …")` in the old function body

Copilot uses AI. Check for mistakes.
- All new C++ APIs must be exposed to Python via ctypes; `argtypes` / `restype` must exactly match the C++ signature
- Handle `bytes` vs `str` encoding for Python 3 in all string-passing paths

## Memory & Resource Safety

- Use RAII / smart pointers (`std::unique_ptr`, `std::shared_ptr`) — no raw owning pointers
- Every allocation freed on **all** paths, including error paths (no FD/memory leaks)
- Thread-shared state protected with mutexes or atomics; document thread-safety guarantees

## LLVM/Clang Compatibility

- Check minimum LLVM version in `CMakeLists.txt` before using new APIs
- Gate version-specific code with `#if LLVM_VERSION_MAJOR >= N`

## Build System

- New optional dependencies guarded with `find_package` + `#ifdef HAVE_*`
- New deps added to both `CMakeLists.txt` and `debian/control`

## Documentation

- Update `docs/reference_guide.md` for new or changed public APIs
- Public functions: Doxygen-style comments (`@param`, `@return`)

## Review Checklist

- [ ] Public C++ API unchanged or deprecated gracefully
- [ ] Python bindings updated to match any C++ signature change
- [ ] No memory/FD leaks; RAII used
- [ ] NULL checks after every `malloc`/`calloc`/`realloc`/`strdup`
- [ ] Error handling consistent (negative errno / `StatusTuple`)
- [ ] Thread safety considered for shared state
- [ ] Architecture-specific code guarded with `#ifdef`
- [ ] LLVM version compatibility maintained
- [ ] `docs/reference_guide.md` updated for new public APIs
- [ ] Build system changes correct (optional deps guarded)
- [ ] Code style consistent (run `scripts/c-style-check.sh`)

## Red Flags — Always Flag

1. Breaking C++ API change without deprecation
2. C++ signature changed but Python bindings not updated
3. Memory or FD leak (missing `close()`, `free()`, destructor)
4. Missing NULL check after allocation
5. Thread-safety violation on shared state
6. Platform-specific code without `#ifdef` guard
7. New LLVM API used without version guard
74 changes: 74 additions & 0 deletions .github/instructions/examples.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
applyTo: "examples/**"
---

# BCC Examples Review Instructions

Examples are **educational** — prioritize clarity over production robustness.

<CriticalRules>
- Focus on **one concept** per example; target **< 150 lines** total.
- Every major BPF step MUST have an inline comment explaining **why**, not just what.
- Header comment MUST describe the concept demonstrated and usage.
- Do NOT add complex argument parsing or production-grade error handling — it obscures the learning point.
- License header MUST be present.
</CriticalRules>

## Required Header Comment

Every example must start with:
```
# example_name.py Brief one-line description
# Demonstrates: [what BCC/eBPF concept this shows]
# USAGE: example_name.py
# Copyright [year] [author] / Licensed under Apache 2.0
```

## Pedagogical Quality

- One BCC concept per example; builds naturally on simpler ones
- Clear learning objective; do not mix maps + arrays + perf buffers + USDT in one example
- Output is labeled (column headers); explain what's being traced
- Minimal error handling: catch `BPF()` failure and `KeyboardInterrupt` only

## Kernel Compatibility

- Note kernel requirements in a comment when using features requiring ≥ 4.x
- Use `BPF.kernel_struct_has_field()` for runtime field detection; never hard-code kernel versions

## File Organization

- `networking/` — network-related examples
- `tracing/` — kernel/userspace tracing
- `usdt_sample/` — USDT examples
- `lua/` — Lua API examples
- `cpp/` — C++ API examples

## What Examples Do NOT Require

Unlike `tools/`, examples do **not** need:
- Man pages, `*_example.txt` files, README.md entries (optional)
- Comprehensive argparse argument handling
- Overhead documentation

## Review Checklist

- [ ] ≤ 150 lines; focuses on a single BCC concept
- [ ] Inline comments explain each BPF step
- [ ] Header comment describes purpose and concept demonstrated
- [ ] License header present
- [ ] Output is labeled and explained
- [ ] Basic error handling present (BPF compile failure, KeyboardInterrupt)
- [ ] Correct subdirectory placement
- [ ] Python 3 compatible
- [ ] No undocumented external dependencies

## Red Flags — Always Flag

1. > 150 lines or mixes too many concepts (belongs in `tools/` instead)
2. Missing inline comments on BPF logic
3. No header comment describing the concept demonstrated
4. Missing license header
5. No output or unexplained/unlabeled output
6. Python 2-only code (`print "..."`, `except Exception, e:`)
7. Undocumented external Python dependencies
40 changes: 40 additions & 0 deletions .github/instructions/instructions.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
applyTo: ".github/instructions/*.instructions.md"
---

# Authoring BCC Instruction Files

These files define Copilot review rules for the BCC project.
When editing them, follow the steps below to avoid writing rules that contradict
the actual codebase.

## Before Writing or Updating Any Rule

1. **API / function examples** — read the actual source before writing:
- Python BCC API → check `src/python/bcc/table.py`
- BPF helper signatures → check `libbpf-tools/*.bpf.c` examples
- Userspace libbpf patterns → check `libbpf-tools/*.c` examples

2. **Conventions (shebang, imports, prefixes, etc.)** — sample the real files:
- `tools/*.py` for Python conventions (shebang)
- `libbpf-tools/*.c` / `*.bpf.c` for C conventions
- `git log --oneline origin/master | head -30` for commit prefix convention (format: `subsystem/toolname:`)

3. **Do not invent or assume** an API method, macro, or convention exists —
verify it in the repo first.

## Scope of Each Instructions File

| File | `applyTo` | Triggers when… |
|------|-----------|----------------|
| `tools.instructions.md` | `tools/**/*.py` | editing a Python tool |
| `libbpf-tools.instructions.md` | `libbpf-tools/**/*` | editing a libbpf tool |
| `core.instructions.md` | `src/cc/**` | editing BCC core library |
| `examples.instructions.md` | `examples/**` | editing an example |
| `instructions.instructions.md` | `.github/instructions/*.instructions.md` | editing these rule files |

## Style

- Keep `<CriticalRules>` short — Copilot has a ~4,000 character review window
- One rule per bullet; no redundancy across files
- Flag blockers explicitly; use 🟡 Warning for non-blockers
83 changes: 83 additions & 0 deletions .github/instructions/libbpf-tools.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
applyTo: "libbpf-tools/**/*"
---

# libbpf-tools (CO-RE) Review Instructions

These are CO-RE (Compile Once - Run Everywhere) tools using libbpf.

<CriticalRules>
- MUST use `vmlinux.h` for kernel types — do NOT redefine structs manually.
- MUST use `BPF_CORE_READ` (or `BPF_CORE_READ_USER` for user-space pointers)
for kernel struct field access — no direct `task->pid` style access.
- MUST NULL-check every BPF map lookup result before dereferencing.
- MUST NULL-check every `malloc()`, `calloc()`, `realloc()`, and `strdup()` in userspace C.
- MUST bounds-check every array index before access.
- BPF functions: flag if stack usage appears to approach or exceed 512 bytes (eBPF verifier hard limit).
- Use `bpf_core_field_exists()` for kernel version compatibility — never `#if LINUX_VERSION_CODE`.
- Use split lifecycle: `__open()` → configure rodata/map sizes → `__load()` → `__attach()`.
Flag `open_and_load()` if rodata fields or map max_entries are configured before load.
- Check return values of ALL attachment calls (`bpf_program__attach_*`).
- Do NOT use old-style map definitions (`bpf_map_def SEC("maps")`).
- Do NOT use hard-coded kernel version numbers or struct offsets.
- Do NOT create duplicate BPF programs with identical logic — use `bpf_program__set_attach_target()` instead.
- When providing both fentry and kprobe fallback paths: both paths must attach to the same
set of kernel functions. Use `bpf_program__set_attach_target()` in the kprobe path to
match the fentry path's attach targets.
</CriticalRules>

## libbpf Object Lifecycle

- Always split: `__open()` → set rodata/map config → `__load()` → `__attach()`
- Flag any use of `open_and_load()` where rodata or map `max_entries` are configured
- Check all return values; use `goto cleanup` pattern
- All resources (skel, FDs, links) freed on all exit paths including errors

## BPF Memory Safety

- NULL-check every `bpf_map_lookup_elem()` result before dereferencing
- Bounds-check every array index: `if (idx >= MAX_ENTRIES) return 0;`
- Check `bpf_probe_read_kernel()` return value: `if (ret < 0) return 0;`
- Keep per-function BPF stack usage well under 512 bytes; use per-CPU maps for large structs
- String reads: always use bounded helpers (`bpf_probe_read_kernel_str`, `bpf_get_current_comm`)

## Userspace Rules

- Output: default **< 80 characters wide**
- Error messages: clear, actionable, include `strerror(errno)` where applicable
- Map FD: check `bpf_map__fd()` result is ≥ 0 before use
- Use existing helpers (`trace_helpers.h`, `map_helpers.h`) — don't duplicate

## Required Files (New Tools)

### Code
1. `libbpf-tools/tool.bpf.c` — BPF program
2. `libbpf-tools/tool.c` — userspace program
3. `libbpf-tools/tool.h` — shared header (if needed)
4. Makefile entry for skeleton generation

### Documentation (enforce as blocker)
5. `man/man8/tool.8` — with **OVERHEAD** and **CAVEATS** sections
6. `README.md` — entry added
7. `libbpf-tools/tool_example.txt` — example output *(recommended; may be omitted if an
equivalent Python tools/ example already exists)*

## Review Checklist

- [ ] CO-RE: `vmlinux.h` used; `BPF_CORE_READ` family for all kernel struct access
- [ ] Lifecycle: split open → configure → load → attach (flag premature `open_and_load`)
- [ ] BPF memory safety: NULL checks after map lookups, bounds checks, stack well under 512 bytes
- [ ] Userspace: NULL checks after all `malloc`/`calloc`/`realloc`/`strdup`
- [ ] All attach/map FD return values checked
- [ ] Resources freed on all paths (`goto cleanup`)
- [ ] BTF-style map definitions (no `bpf_map_def`)
- [ ] No hard-coded kernel versions or offsets
- [ ] No duplicate BPF programs; fentry and kprobe paths cover same attach targets
- [ ] Output < 80 chars wide
- [ ] Makefile skeleton generation entry present
- [ ] Documentation: man page + README entry (new tools); example file recommended

## References

- [libbpf Documentation](https://github.com/libbpf/libbpf)
- [BPF CO-RE Reference](https://nakryiko.com/posts/bpf-portability-and-co-re/)
33 changes: 33 additions & 0 deletions .github/instructions/tools.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
applyTo: "tools/**/*.py"
---

# BCC Tools (Python/BCC API) Review Instructions

Tools run in **mission-critical environments as root** — correctness and safety are mandatory.

<CriticalRules>
- BPF C code: MUST NULL-check every `map.lookup(&key)` result before dereferencing.
- BPF C code: MUST bounds-check every array index before access.
- BPF C code: flag if stack usage appears to approach or exceed 512 bytes (eBPF verifier hard limit).
- Default output MUST be under 80 characters wide.
- New tools MUST include man page (`man/man8/`) with **OVERHEAD** and **CAVEATS** sections.
</CriticalRules>

## BCC API Safety

- Map lookup: use `table[key]` with `try/except KeyError`, or `table.get(key)` — check result is not `None` before use
- BPF C macro `map.lookup(&key)` returns a pointer — NULL means key not found; always guard before dereference
- Prefer map-based aggregation over per-event output for high-frequency events; filter in BPF, not Python

## Required Documentation (New Tools)

1. `man/man8/toolname.8` — with **OVERHEAD** and **CAVEATS** sections
2. `tools/toolname_example.txt` — example output
3. `README.md` — entry added
4. `tests/python/test_tools_smoke.py` — smoke test entry

## Kernel Compatibility

- Use `BPF.kernel_struct_has_field()` for runtime struct field detection — never hard-code kernel version numbers
- New options must not break existing default behavior
Loading
Loading