Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tw4452852/zbpf
Writing eBPF in Zig
https://github.com/tw4452852/zbpf
bpf ebpf tracing zig
Last synced: about 1 month ago
JSON representation
Writing eBPF in Zig
- Host: GitHub
- URL: https://github.com/tw4452852/zbpf
- Owner: tw4452852
- License: gpl-3.0
- Created: 2023-04-11T01:46:45.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-09-12T06:32:34.000Z (3 months ago)
- Last Synced: 2024-09-12T16:08:57.934Z (3 months ago)
- Topics: bpf, ebpf, tracing, zig
- Language: Zig
- Homepage: https://tw4452852.github.io/zbpf/
- Size: 4.7 MB
- Stars: 100
- Watchers: 4
- Forks: 6
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-zig - tw4452852/zbpf
README
# zbpf
Writing eBPF in Zig. Thanks to Zig's comptime and BTF, we can equip eBPF with strong type system both at comptime and runtime!## Notable advantages when writing eBPF program with `zbpf`
### Different available methods based on the type of program's context
Suppose you want to trace the kernel function [path_listxattr](https://github.com/torvalds/linux/blob/7475e51b87969e01a6812eac713a1c8310372e8a/fs/xattr.c#L856-L857),
and here's its prototype:```
static ssize_t path_listxattr(const char __user *pathname, char __user *list,
size_t size, unsigned int lookup_flags)
```
As you can see, it has 4 input parameters and return type is `ssize_t`.
With `ctx = bpf.Kprobe{.name = "path_listxattr"}.Ctx()`, you could retrieve
the input parameter with `ctx.arg0()`, `ctx.arg1()`, `ctx.arg2()` and `ctx.arg3()` respectively,
and return value with `ctx.ret()`.
the type will be consistent with the above prototype. If you try to access a non-existing
parameter, e.g. `ctx.arg4()`, you will get a compilation error.This also applies to `syscall` with `bpf.Ksyscall`, `tracepoint` with `bpf.Tracepoint` and
`fentry` with `bpf.Fentry`.### No more tedious error handling
When writing in C, you always have to check the error conditions
(the return value of the helper function, pointer validation, ...)
With `zbpf`, you won't care about the these cases, we handle it under the hood for you,
just focus on the business logic.The following are some examples:
- `bpf.Map` takes care BPF map's `update` and `delete` error.
- `bpf.PerfEventArray` handles event output failure.
- `bpf.RingBuffer` also handles space reservation.
- `bpf.Xdp` validates the pointer for you.If some error happens, you could get all the information (file, line number, return value ...)
you need to debug in the kernel trace buffer:```
~> sudo bpftool prog tracelog
test-11717 [005] d..21 10990692.273976: bpf_trace_printk: error occur at src/bpf/map.zig:110 return -2
```## How to use
## Prerequisite
- Make sure the linux kernel is built with `CONFIG_DEBUG_INFO_BTF=y`.
- The only runtime library is `libc` (this is not even necessary if you build with musl-libc).## Build
- Download the [lastest Zig](https://ziglang.org/download/).
- Clone this repostory.
- Build with `zig build -Dbpf=/path/to/your/bpf/prog.zig -Dmain=/path/to/your/main.zig`.For cross-compiling, you could specify the target with `-Dtarget=`,
the list of all supported targets could be retrieved by `zig targets`.Moreover, you could specify the target kernel with `-Dvmlinux=/path/to/vmlinux`
to extract BTF from it, otherwise, current kernel's BTF will be used.That's all! The generated binary is located at `./zig-out/bin/zbpf`,
feel free to run it on your target machine.Here's the [Documentations generated by Zig's AutoDoc](https://tw4452852.github.io/zbpf)
for you reference.## Tools/trace
`trace` is a tool built on top of `zbpf` framework to trace kernel functions and syscalls.
It's heavily inspired by [retsnoop](https://github.com/anakryiko/retsnoop).
One improvement I made (which is also what I feel when using retsnoop) is that `trace` support
show parameters according its type (thanks to the Zig type system).
This is very helpful when debugging linux kernel.
For more details, you could check the implementation: [BPF side](https://github.com/tw4452852/zbpf/blob/main/src/tools/trace/trace.bpf.zig)
and [Host side](https://github.com/tw4452852/zbpf/blob/main/src/tools/trace/trace.zig).You could specify the kernel functions you want to trace with: `zig build trace -Dkprobe= -Dkprobe=...`
And for system calls: `zig build trace -Dsyscall= -Dsyscall=...`.
Moreover, if you also want to capture the function's arguments, append the argument specifier, something like this:
`-Dkprobe=:arg0,arg1...`, it also supports access to the deeper field if the argument is a pointer to a struct:
`-Dkprobe=:arg0.field1.field0`.
You could even control how the argument is shown by using all the supported specifier by Zig's `std.fmt`, something like this:
`-Dkprobe=:arg0.field1.field0/x` will show `arg0.field1.field0` in hexadecimal notation.
Capturing call stack is also supported, append keyword `stack`, for example `-Dkprobe=:arg0,stack`.And here's a quick demo:
[![asciicast](https://asciinema.org/a/675689.svg)](https://asciinema.org/a/675689)
## Samples
For each supported feature, we have the corresponding unit test.
You could find them under `samples/` (BPF side) and `src/tests` (Host side).
Build it with `zig build test -Dtest=` and run it with `sudo zig-out/bin/test`.Name | BPF side | Host side
--- | --- | ---
exit | [source](samples/exit.zig) | [source](src/tests/exit.zig)
panic | [source](samples/panic.zig) | [source](src/tests/panic.zig)
trace_printk | [source](samples/trace_printk.zig) | [source](src/tests/trace_printk.zig)
array | [source](samples/array.zig) | [source](src/tests/array.zig)
hash | [source](samples/hash.zig) | [source](src/tests/hash.zig)
perf_event | [source](samples/perf_event.zig) | [source](src/tests/perf_event.zig)
ringbuf | [source](samples/ringbuf.zig) | [source](src/tests/ringbuf.zig)
tracepoint | [source](samples/tracepoint.zig) | [source](src/tests/tracepoint.zig)
iterator | [source](samples/iterator.zig) | [source](src/tests/iterator.zig)
fentry | [source](samples/fentry.zig) | [source](src/tests/fentry.zig)
kprobe | [source](samples/kprobe.zig) | [source](src/tests/kprobe.zig)
kmulprobe | [source](samples/kmulprobe.zig) | [source](src/tests/kmulprobe.zig)
xdp ping | [source](samples/xdp_ping.zig) | [source](src/tests/xdp_ping.zig)
kfunc | [source](samples/kfunc.zig) | [source](src/tests/kfunc.zig)
stack_trace | [source](samples/stacktrace.zig) | [source](src/tests/stacktrace.zig)**Have fun!**