-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
# bpftime-aot cli | ||
|
||
An cli for help to compile eBPF to native ELF. | ||
|
||
It can be used to compile eBPF insns to native insns with helpers, maps define, or load native ELF to run in the userspace runtime. | ||
|
||
The tool can be found in <https://github.com/eunomia-bpf/bpftime/tree/master/tools/aot> | ||
|
||
If you are looking for a library, please see <https://github.com/eunomia-bpf/llvmbpf> | ||
|
||
## Usage | ||
|
||
```console | ||
# bpftime-aot help | ||
Usage: /home/yunwei/ebpf-xdp-dpdk/build-bpftime/bpftime/tools/aot/bpftime-aot [--help] [--version] {build,compile,run} | ||
|
||
Optional arguments: | ||
-h, --help shows help message and exits | ||
-v, --version prints version information and exits | ||
|
||
Subcommands: | ||
build Build native ELF(s) from eBPF ELF. Each program in the eBPF ELF will be built into a single native ELF | ||
compile Compile the eBPF program loaded in shared memory | ||
run Run an native eBPF program | ||
``` | ||
|
||
## Build ELF from shared mnemory and use it with helpers and maps | ||
|
||
load the eBPF programs and maps to shared memory: | ||
|
||
```sh | ||
LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so example/malloc/malloc | ||
``` | ||
|
||
The eBPF code here is: | ||
|
||
```c | ||
#define BPF_NO_GLOBAL_DATA | ||
#include <vmlinux.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(max_entries, 1024); | ||
__type(key, u32); | ||
__type(value, u64); | ||
} libc_malloc_calls_total SEC(".maps"); | ||
|
||
static int increment_map(void *map, void *key, u64 increment) | ||
{ | ||
u64 zero = 0, *count = bpf_map_lookup_elem(map, key); | ||
if (!count) { | ||
bpf_map_update_elem(map, key, &zero, BPF_NOEXIST); | ||
count = bpf_map_lookup_elem(map, key); | ||
if (!count) { | ||
return 0; | ||
} | ||
} | ||
u64 res = *count + increment; | ||
bpf_map_update_elem(map, key, &res, BPF_EXIST); | ||
|
||
return *count; | ||
} | ||
|
||
SEC("uprobe/libc.so.6:malloc") | ||
int do_count(struct pt_regs *ctx) | ||
{ | ||
u32 pid = bpf_get_current_pid_tgid() >> 32; | ||
|
||
bpf_printk("malloc called from pid %d\n", pid); | ||
|
||
increment_map(&libc_malloc_calls_total, &pid, 1); | ||
|
||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "GPL"; | ||
``` | ||
then build the native ELF from shared memory: | ||
```sh | ||
bpftime-aot compile | ||
``` | ||
|
||
You will get a native ELF file named `do_count.o`. | ||
|
||
You can link it with your program and execute it: | ||
|
||
```sh | ||
cd bpftime/tools/aot/example | ||
clang -O2 main.c do_count.o -o malloc | ||
``` | ||
|
||
The drive program is like: | ||
|
||
```c | ||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <unistd.h> | ||
#include <stdlib.h> | ||
|
||
int bpf_main(void* ctx, uint64_t size); | ||
|
||
// bpf_printk | ||
uint64_t _bpf_helper_ext_0006(uint64_t fmt, uint64_t fmt_size, ...) | ||
{ | ||
const char *fmt_str = (const char *)fmt; | ||
va_list args; | ||
#pragma GCC diagnostic push | ||
#pragma GCC diagnostic ignored "-Wformat-nonliteral" | ||
#pragma GCC diagnostic ignored "-Wvarargs" | ||
va_start(args, fmt_str); | ||
long ret = vprintf(fmt_str, args); | ||
#pragma GCC diagnostic pop | ||
va_end(args); | ||
return 0; | ||
} | ||
|
||
// bpf_get_current_pid_tgid | ||
uint64_t _bpf_helper_ext_0014(void) | ||
{ | ||
static int tgid = -1; | ||
static int tid = -1; | ||
if (tid == -1) | ||
tid = gettid(); | ||
if (tgid == -1) | ||
tgid = getpid(); | ||
return ((uint64_t)tgid << 32) | tid; | ||
} | ||
|
||
// here we use an var to mock the map. | ||
uint64_t counter_map = 0; | ||
|
||
// bpf_map_lookup_elem | ||
void * _bpf_helper_ext_0001(void *map, const void *key) | ||
{ | ||
printf("bpf_map_lookup_elem\n"); | ||
return &counter_map; | ||
} | ||
|
||
// bpf_map_update_elem | ||
long _bpf_helper_ext_0002(void *map, const void *key, const void *value, uint64_t flags) | ||
{ | ||
printf("bpf_map_update_elem\n"); | ||
if (value == NULL) { | ||
printf("value is NULL\n"); | ||
return -1; | ||
} | ||
uint64_t* value_ptr = (uint64_t*)value_ptr; | ||
counter_map = *value_ptr; | ||
printf("counter_map: %lu\n", counter_map); | ||
return 0; | ||
} | ||
|
||
uint64_t __lddw_helper_map_by_fd(uint32_t id) { | ||
printf("map_by_fd\n"); | ||
return 0; | ||
} | ||
|
||
int main() { | ||
printf("Hello, World!\n"); | ||
bpf_main(NULL, 0); | ||
return 0; | ||
} | ||
``` | ||
Note by loading eBPF programs with libbpf and LD_PRELOAD, maps, global variables, and helpers are already relocated in shared memory, so you can use them directly in your program. For example, the input of `__lddw_helper_map_by_fd` function would be the actual map id in shared memory. | ||
You can refer to `example/malloc.json` for details about how the maps are relocated. | ||
## Compile from eBPF bytecode ELF | ||
You can also compile the eBPF bytecode ELF to native ELF: | ||
```sh | ||
bpftime-aot build bpftime/example/minimal/.output/uprobe.bpf.o -e | ||
``` | ||
|
||
In this way, the relocation of maps, global variables, and helpers will not be done. The helpers is still works. | ||
|
||
## run native ELF | ||
|
||
Given a eBPF code: | ||
|
||
```c | ||
#define BPF_NO_GLOBAL_DATA | ||
#include <vmlinux.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
SEC("uprobe/./victim:target_func") | ||
int do_uprobe_trace(struct pt_regs *ctx) | ||
{ | ||
bpf_printk("target_func called.\n"); | ||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "GPL"; | ||
``` | ||
The native C code after relocation is like: | ||
```c | ||
int _bpf_helper_ext_0006(char* arg0); | ||
int bpf_main(void *ctx) | ||
{ | ||
_bpf_helper_ext_0006("target_func called.\n"); | ||
return 0; | ||
} | ||
``` | ||
|
||
Compile it with `clang -O3 -c -o do_uprobe_trace.o do_uprobe_trace.c`, and you can load it with AOT runtime. | ||
|
||
You can simply run the native ELF: | ||
|
||
```console | ||
# bpftime-aot run do_uprobe_trace.o | ||
[2024-03-24 21:57:53.446] [info] [llvm_jit_context.cpp:81] Initializing llvm | ||
[2024-03-24 21:57:53.446] [info] [llvm_jit_context.cpp:204] LLVM-JIT: Loading aot object | ||
target_func called. | ||
[2024-03-24 21:57:53.449] [info] [main.cpp:190] Output: 0 | ||
``` | ||
|
||
## emit llvm ir | ||
|
||
```sh | ||
bpftime-aot compile -e | ||
``` | ||
|
||
or: | ||
|
||
```sh | ||
bpftime-aot build -e minimal.bpf.o | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# bpftimetool | ||
|
||
Similar to bpftool, bpftimetool is tools to inspect or operate the shared memory status of the target process. | ||
|
||
It supports: | ||
|
||
- serialize the shared memory status to json | ||
- load the json and restore the status in shared memory | ||
- run ebpf program (XDP or others) and measure the time | ||
|
||
The tool can be found in <https://github.com/eunomia-bpf/bpftime/tree/master/tools/bpftimetool> | ||
|
||
You may also use bpftool with the syscall server. | ||
|
||
## Export data in json | ||
|
||
```console | ||
$ ~/.bpftime/bpftimetool export res.json | ||
[2023-10-23 18:45:25.893] [info] Global shm constructed. shm_open_type 1 for bpftime_maps_shm | ||
[2023-10-23 18:45:25.894] [info] bpf_map_handler name=.rodata.str1.1 found at 3 | ||
[2023-10-23 18:45:25.894] [info] find prog fd=4 name=do_uprobe_trace | ||
[2023-10-23 18:45:25.894] [info] bpf_perf_event_handler found at 5 | ||
INFO [93828]: Global shm destructed | ||
``` | ||
|
||
## Import data from json | ||
|
||
```console | ||
SPDLOG_LEVEL=Debug ~/.bpftime/bpftimetool import /home/yunwei/bpftime/tools/bpftimetool/minimal.json | ||
[2023-10-23 19:02:04.955] [info] Global shm constructed. shm_open_type 3 for bpftime_maps_shm | ||
[2023-10-23 19:02:04.955] [info] import handler fd 3 {"attr":{"btf_id":2,"btf_key_type_id":0,"btf_value_type_id":0,"btf_vmlinux_value_type_id":0,"flags":128,"ifindex":0,"key_size":4,"map_extra":0,"map_type":2,"max_entries":1,"value_size":21},"name":".rodata.str1.1","type":"bpf_map_handler"} | ||
[2023-10-23 19:02:04.955] [info] import handler type bpf_map_handler fd 3 | ||
[2023-10-23 19:02:04.956] [info] import handler fd 4 {"attr":{"attach_fds":[5],"cnt":16,"insns":"b701000065642e0a631af8ff0000000018010000756e63200000000063616c6c7b1af0ff0000000018010000746172670000000065745f667b1ae8ff00000000b701000000000000731afcff00000000bfa100000000000007010000e8ffffffb7020000150000008500000006000000b7000000000000009500000000000000","type":0},"name":"do_uprobe_trace","type":"bpf_prog_handler"} | ||
[2023-10-23 19:02:04.956] [info] import handler type bpf_prog_handler fd 4 | ||
[2023-10-23 19:02:04.956] [info] import handler fd 5 {"attr":{"_module_name":"example/minimal/victim","offset":4457,"pid":-1,"ref_ctr_off":0,"tracepoint_id":-1,"type":6},"type":"bpf_perf_event_handler"} | ||
[2023-10-23 19:02:04.956] [info] import handler type bpf_perf_event_handler fd 5 | ||
INFO [99712]: Global shm destructed | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters