diff --git a/GPTtrace.py b/GPTtrace.py index 82d82b9..4a278b4 100755 --- a/GPTtrace.py +++ b/GPTtrace.py @@ -26,8 +26,6 @@ def pretty_print(input, lexer=MarkdownLexer, *args, **kwargs): # print = pretty_print - - def main(): parser = argparse.ArgumentParser( prog="GPTtrace", @@ -111,7 +109,6 @@ def main(): input_data = f.read() if args.verbose: print(input_data) - print("-"*len(info)) _, session = generate_result( chatbot, input_data, conv_uuid, args.verbose) print(f"Trained session: {session}") diff --git a/prompts/0.md b/prompts/0.md new file mode 100644 index 0000000..6fab7f4 --- /dev/null +++ b/prompts/0.md @@ -0,0 +1 @@ +I'll give you a few examples of how to write eBPF programs. You can use these examples to learn how to write eBPF programs, they will cover libbpf, bcc and bpftrace. diff --git a/prompts/1.1.md b/prompts/1.1.md new file mode 100644 index 0000000..d4f4b27 --- /dev/null +++ b/prompts/1.1.md @@ -0,0 +1,42 @@ + +This is a minimal libbpf program using kprobe: + +# kprobe + +```c +#include "vmlinux.h" +#include +#include +#include + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +SEC("kprobe/do_unlinkat") +int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name) +{ + pid_t pid; + const char *filename; + + pid = bpf_get_current_pid_tgid() >> 32; + filename = BPF_CORE_READ(name, name); + bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename); + return 0; +} + +SEC("kretprobe/do_unlinkat") +int BPF_KRETPROBE(do_unlinkat_exit, long ret) +{ + pid_t pid; + + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); + return 0; +} +``` + +kprobe 是 eBPF 用于处理内核空间入口和出口(返回)探针(kprobe 和 kretprobe)的一个例子。它将 kprobe 和 kretprobe BPF 程序附加到 do_unlinkat() 函数上,并使用 bpf_printk() 宏分别记录 PID、文件名和返回值。 + + +eunomia-bpf 是一个结合 Wasm 的开源 eBPF 动态加载运行时和开发工具链,它的目的是简化 eBPF 程序的开发、构建、分发、运行。可以参考 下载和安装 ecc 编译工具链和 ecli 运行时。 + +我还没有说完,我会继续说。 \ No newline at end of file diff --git a/prompts/1.2.md b/prompts/1.2.md new file mode 100644 index 0000000..643f4a6 --- /dev/null +++ b/prompts/1.2.md @@ -0,0 +1,35 @@ + +要编译这个程序,请使用 ecc 工具: + +```console +$ ecc kprobe-link.bpf.c +Compiling bpf object... +Packing ebpf object and config into package.json... +``` + +然后运行: + +```console +sudo ecli package.json +``` + +在另外一个窗口中: + +```shell +touch test1 +rm test1 +touch test2 +rm test2 +``` + +在 /sys/kernel/debug/tracing/trace_pipe 文件中,应该能看到类似下面的 kprobe 演示输出: + +```shell +$ sudo cat /sys/kernel/debug/tracing/trace_pipe + rm-9346 [005] d..3 4710.951696: bpf_trace_printk: KPROBE ENTRY pid = 9346, filename = test1 + rm-9346 [005] d..4 4710.951819: bpf_trace_printk: KPROBE EXIT: ret = 0 + rm-9346 [005] d..3 4710.951852: bpf_trace_printk: KPROBE ENTRY pid = 9346, filename = test2 + rm-9346 [005] d..4 4710.951895: bpf_trace_printk: KPROBE EXIT: ret = 0 +``` + +If you learned and remembered the result for libbpf program, please tell me OK. diff --git a/prompts/1.3.md b/prompts/1.3.md new file mode 100644 index 0000000..2f359ee --- /dev/null +++ b/prompts/1.3.md @@ -0,0 +1,33 @@ +This is another libbpf program: + +# 在 eBPF 中使用 libbpf 捕获进程打开文件的系统调用集合 + +首先,我们需要编写一段 eBPF 程序来捕获进程打开文件的系统调用,具体实现如下: + +```c +#include +#include + +/// @description "Process ID to trace" +const volatile int pid_target = 0; + +SEC("tracepoint/syscalls/sys_enter_openat") +int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter* ctx) +{ + u64 id = bpf_get_current_pid_tgid(); + u32 pid = id; +if (pid_target && pid_target != pid) + return false; + // Use bpf_printk to print the process information + bpf_printk("Process ID: %d enter sys openat\n", pid); + return 0; +} + +/// "Trace open family syscalls." +char LICENSE[] SEC("license") = "GPL"; +``` + + +上面的 eBPF 程序通过定义函数 tracepoint__syscalls__sys_enter_openat 并使用 SEC 宏把它们附加到 sys_enter_openat 的 tracepoint(即在进入 openat 系统调用时执行)。这个函数通过使用 bpf_get_current_pid_tgid 函数获取调用 openat 系统调用的进程 ID,并使用 bpf_printk 函数在内核日志中打印出来。 + +​If you learned and remembered the result for libbpf program, please tell me OK. diff --git a/prompts/1.md b/prompts/1.md index e7d8c5c..be5ab46 100644 --- a/prompts/1.md +++ b/prompts/1.md @@ -1,3 +1,4 @@ + This is an libbpf program: a minimal example of a BPF application installs a tracepoint handler which is triggered by write syscall @@ -27,4 +28,12 @@ int handle_tp(void *ctx) bpf_printk("BPF triggered from PID %d.\n", pid); return 0; } -``` \ No newline at end of file +``` + +这段程序通过定义一个 handle_tp 函数并使用 SEC 宏把它附加到 sys_enter_write tracepoint(即在进入 write 系统调用时执行)。该函数通过使用 bpf_get_current_pid_tgid 和 bpf_printk 函数获取调用 write 系统调用的进程 ID,并在内核日志中打印出来。 + +- `bpf_trace_printk()`: 一种将信息输出到trace_pipe(/sys/kernel/debug/tracing/trace_pipe)简单机制。 在一些简单用例中这样使用没有问题, but它也有一些限制:最多 3 参数; 第一个参数必须是%s(即字符串);同时trace_pipe在内核中全局共享,其他并行使用trace_pipe的程序有可能会将 trace_pipe 的输出扰乱。 一个更好的方式是通过 BPF_PERF_OUTPUT(), 稍后将会讲到。 +- `void *ctx`:ctx本来是具体类型的参数, 但是由于我们这里没有使用这个参数,因此就将其写成void *类型。 +- `return 0`;:必须这样,返回 0 + +If you learned and remembered the result, please tell me OK. diff --git a/prompts/3.1.md b/prompts/3.1.md new file mode 100644 index 0000000..5708d7c --- /dev/null +++ b/prompts/3.1.md @@ -0,0 +1,34 @@ +You are now a translater from human language to shell bpftrace command. +Here are some examples of what you can do with bpftrace shell command, the upper line is the description of the command, the lower line is the command itself. + +# Files opened by process +bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)); }' + +# Syscall count by program +bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' + +# Read bytes by process: +bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }' + +# Read size distribution by process: +bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args->ret); }' + +# Show per-second syscall rates: +bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @ = count(); } interval:s:1 { print(@); clear(@); }' + +# Trace disk size by process +bpftrace -e 'tracepoint:block:block_rq_issue { printf("%d %s %d\n", pid, comm, args->bytes); }' + +# Count page faults by process +bpftrace -e 'software:faults:1 { @[comm] = count(); }' + +# Count LLC cache misses by process name and PID (uses PMCs): +bpftrace -e 'hardware:cache-misses:1000000 { @[comm, pid] = count(); }' + +# Profile user-level stacks at 99 Hertz, for PID 189: +bpftrace -e 'profile:hz:99 /pid == 189/ { @[ustack] = count(); }' + +# Files opened, for processes in the root cgroup-v2 +bpftrace -e 'tracepoint:syscalls:sys_enter_openat /cgroup == cgroupid("/sys/fs/cgroup/unified/mycg")/ { printf("%s\n", str(args->filename)); }' + +After you read and learn about bpftrace, I will ask you to write a bpftrace command to do something. diff --git a/prompts/3.md b/prompts/3.md index b0a6460..6b64af0 100644 --- a/prompts/3.md +++ b/prompts/3.md @@ -1,34 +1,29 @@ -You are now a translater from human language to shell bpftrace command. -Here are some examples of what you can do with bpftrace shell command: +I want you to be a translater from human language to shell bpftrace command, here are some tips and examples about writing bpftrace programs: -# Files opened by process -bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)); }' +bpftrace program Syntax are like this: -# Syscall count by program -bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' +```sh +probe[,probe,...] /filter/ { action } +``` -# Read bytes by process: -bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }' +The probe specifies what events to instrument, the filter is optional and can filter down the events based on a boolean expression, and the action is the mini program that runs. -# Read size distribution by process: -bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args->ret); }' +Here's hello world: -# Show per-second syscall rates: -bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @ = count(); } interval:s:1 { print(@); clear(@); }' +```sh +bpftrace -e 'BEGIN { printf("Hello eBPF!\n"); }' +``` -# Trace disk size by process -bpftrace -e 'tracepoint:block:block_rq_issue { printf("%d %s %d\n", pid, comm, args->bytes); }' +The probe is BEGIN, a special probe that runs at the beginning of the program (like awk). There's no filter. The action is a printf() statement. -# Count page faults by process -bpftrace -e 'software:faults:1 { @[comm] = count(); }' +Now a real example: -# Count LLC cache misses by process name and PID (uses PMCs): -bpftrace -e 'hardware:cache-misses:1000000 { @[comm, pid] = count(); }' +```sh +bpftrace -e 'kretprobe:vfs_read /pid == 181/ { @bytes = hist(retval); }' +``` -# Profile user-level stacks at 99 Hertz, for PID 189: -bpftrace -e 'profile:hz:99 /pid == 189/ { @[ustack] = count(); }' +This uses a kretprobe to instrument the return of the sys_read() kernel function. -# Files opened, for processes in the root cgroup-v2 -bpftrace -e 'tracepoint:syscalls:sys_enter_openat /cgroup == cgroupid("/sys/fs/cgroup/unified/mycg")/ { printf("%s\n", str(args->filename)); }' +If the PID is 181, a special map variable @bytes is populated with a log2 histogram function with the return value retval of sys_read(). This produces a histogram of the returned read size for PID 181. Is your app doing lots of 1 byte reads? Maybe that can be optimized. -After you read and learn about bpftrace, I will ask you to write a bpftrace command to do something. +If you have learned about how to write bpftrace shell commands, please tell me OK.