diff --git a/pkg/proc/internal/ebpf/bpf/include/function_vals.bpf.h b/pkg/proc/internal/ebpf/bpf/include/function_vals.bpf.h index f26c78c876..6b0b8c8275 100644 --- a/pkg/proc/internal/ebpf/bpf/include/function_vals.bpf.h +++ b/pkg/proc/internal/ebpf/bpf/include/function_vals.bpf.h @@ -1,43 +1,41 @@ -#include - // function_parameter stores information about a single parameter to a function. typedef struct function_parameter { - // Type of the parameter as defined by the reflect.Kind enum. - unsigned int kind; - // Size of the variable in bytes. - unsigned int size; - - // Offset from stack pointer. This should only be set from the Go side. - int offset; - - // If true, the parameter is passed in a register. - bool in_reg; - // The number of register pieces the parameter is passed in. - int n_pieces; - // If in_reg is true, this represents the registers that the parameter is passed in. - // This is an array because the number of registers may vary and the parameter may be - // passed in multiple registers. - int reg_nums[6]; - - // The following are filled in by the eBPF program. - size_t daddr; // Data address. - char val[0x30]; // Value of the parameter. - char deref_val[0x30]; // Dereference value of the parameter. + // Type of the parameter as defined by the reflect.Kind enum. + unsigned int kind; + // Size of the variable in bytes. + unsigned int size; + + // Offset from stack pointer. This should only be set from the Go side. + int offset; + + // If true, the parameter is passed in a register. + bool in_reg; + // The number of register pieces the parameter is passed in. + int n_pieces; + // If in_reg is true, this represents the registers that the parameter is passed in. + // This is an array because the number of registers may vary and the parameter may be + // passed in multiple registers. + int reg_nums[6]; + + // The following are filled in by the eBPF program. + size_t daddr; // Data address. + char val[0x30]; // Value of the parameter. + char deref_val[0x30]; // Dereference value of the parameter. } function_parameter_t; // function_parameter_list holds info about the function parameters and // stores information on up to 6 parameters. typedef struct function_parameter_list { - unsigned int goid_offset; // Offset of the `goid` struct member. - long long g_addr_offset; // Offset of the Goroutine struct from the TLS segment. - int goroutine_id; + unsigned int goid_offset; // Offset of the `goid` struct member. + long long g_addr_offset; // Offset of the Goroutine struct from the TLS segment. + int goroutine_id; - unsigned long long int fn_addr; - bool is_ret; + unsigned long long int fn_addr; + bool is_ret; - unsigned int n_parameters; // number of parameters. - function_parameter_t params[6]; // list of parameters. + unsigned int n_parameters; // number of parameters. + function_parameter_t params[6]; // list of parameters. - unsigned int n_ret_parameters; // number of return parameters. - function_parameter_t ret_params[6]; // list of return parameters. + unsigned int n_ret_parameters; // number of return parameters. + function_parameter_t ret_params[6]; // list of return parameters. } function_parameter_list_t; diff --git a/pkg/proc/internal/ebpf/bpf/include/trace.bpf.h b/pkg/proc/internal/ebpf/bpf/include/trace.bpf.h index 971db59fa4..e037cb58d4 100644 --- a/pkg/proc/internal/ebpf/bpf/include/trace.bpf.h +++ b/pkg/proc/internal/ebpf/bpf/include/trace.bpf.h @@ -1,5 +1,6 @@ #include "vmlinux.h" #include "function_vals.bpf.h" +#include #include #include @@ -7,15 +8,10 @@ // Ring buffer to handle communication of variable values back to userspace. struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, BPF_MAX_VAR_SIZ); + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, BPF_MAX_VAR_SIZ); } events SEC(".maps"); -struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, BPF_MAX_VAR_SIZ); -} heap SEC(".maps"); - // Map which uses instruction address as key and function parameter info as the value. struct { __uint(max_entries, 42); diff --git a/pkg/proc/internal/ebpf/bpf/trace.bpf.c b/pkg/proc/internal/ebpf/bpf/trace.bpf.c index 584c71b9fa..e51aa5a611 100644 --- a/pkg/proc/internal/ebpf/bpf/trace.bpf.c +++ b/pkg/proc/internal/ebpf/bpf/trace.bpf.c @@ -1,5 +1,4 @@ #include "include/trace.bpf.h" -#include #define STRING_KIND 24 @@ -12,8 +11,8 @@ int parse_string_param(struct pt_regs *ctx, function_parameter_t *param) { u64 str_len; size_t str_addr; - memcpy(&str_addr, param->val, sizeof(str_addr)); - memcpy(&str_len, param->val + sizeof(str_addr), sizeof(str_len)); + __builtin_memcpy(&str_addr, param->val, sizeof(str_addr)); + __builtin_memcpy(&str_len, param->val + sizeof(str_addr), sizeof(str_len)); param->daddr = str_addr; if (str_addr != 0) { @@ -42,72 +41,72 @@ int parse_param_stack(struct pt_regs *ctx, function_parameter_t *param) { __always_inline void get_value_from_register(struct pt_regs *ctx, void *dest, int reg_num) { switch (reg_num) { - case 0: // RAX - memcpy(dest, &ctx->ax, sizeof(ctx->ax)); - break; - case 1: // RDX - memcpy(dest, &ctx->dx, sizeof(ctx->dx)); - break; - case 2: // RCX - memcpy(dest, &ctx->cx, sizeof(ctx->cx)); - break; - case 3: // RBX - memcpy(dest, &ctx->bx, sizeof(ctx->bx)); - break; - case 4: // RSI - memcpy(dest, &ctx->si, sizeof(ctx->si)); - break; - case 5: // RDI - memcpy(dest, &ctx->di, sizeof(ctx->di)); - break; - case 6: // RBP - memcpy(dest, &ctx->bp, sizeof(ctx->bp)); - break; - case 7: // RSP - memcpy(dest, &ctx->sp, sizeof(ctx->sp)); - break; - case 8: // R8 - memcpy(dest, &ctx->r8, sizeof(ctx->r8)); - break; - case 9: // R9 - memcpy(dest, &ctx->r9, sizeof(ctx->r9)); - break; - case 10: // R10 - memcpy(dest, &ctx->r10, sizeof(ctx->r10)); - break; - case 11: // R11 - memcpy(dest, &ctx->r11, sizeof(ctx->r11)); - break; - case 12: // R12 - memcpy(dest, &ctx->r12, sizeof(ctx->r12)); - break; - case 13: // R13 - memcpy(dest, &ctx->r13, sizeof(ctx->r13)); - break; - case 14: // R14 - memcpy(dest, &ctx->r14, sizeof(ctx->r14)); - break; - case 15: // R15 - memcpy(dest, &ctx->r15, sizeof(ctx->r15)); - break; + case 0: // RAX + __builtin_memcpy(dest, &ctx->ax, sizeof(ctx->ax)); + break; + case 1: // RDX + __builtin_memcpy(dest, &ctx->dx, sizeof(ctx->dx)); + break; + case 2: // RCX + __builtin_memcpy(dest, &ctx->cx, sizeof(ctx->cx)); + break; + case 3: // RBX + __builtin_memcpy(dest, &ctx->bx, sizeof(ctx->bx)); + break; + case 4: // RSI + __builtin_memcpy(dest, &ctx->si, sizeof(ctx->si)); + break; + case 5: // RDI + __builtin_memcpy(dest, &ctx->di, sizeof(ctx->di)); + break; + case 6: // RBP + __builtin_memcpy(dest, &ctx->bp, sizeof(ctx->bp)); + break; + case 7: // RSP + __builtin_memcpy(dest, &ctx->sp, sizeof(ctx->sp)); + break; + case 8: // R8 + __builtin_memcpy(dest, &ctx->r8, sizeof(ctx->r8)); + break; + case 9: // R9 + __builtin_memcpy(dest, &ctx->r9, sizeof(ctx->r9)); + break; + case 10: // R10 + __builtin_memcpy(dest, &ctx->r10, sizeof(ctx->r10)); + break; + case 11: // R11 + __builtin_memcpy(dest, &ctx->r11, sizeof(ctx->r11)); + break; + case 12: // R12 + __builtin_memcpy(dest, &ctx->r12, sizeof(ctx->r12)); + break; + case 13: // R13 + __builtin_memcpy(dest, &ctx->r13, sizeof(ctx->r13)); + break; + case 14: // R14 + __builtin_memcpy(dest, &ctx->r14, sizeof(ctx->r14)); + break; + case 15: // R15 + __builtin_memcpy(dest, &ctx->r15, sizeof(ctx->r15)); + break; } } __always_inline int parse_param_registers(struct pt_regs *ctx, function_parameter_t *param) { switch (param->n_pieces) { - case 6: - get_value_from_register(ctx, param->val+40, param->reg_nums[5]); - case 5: - get_value_from_register(ctx, param->val+32, param->reg_nums[4]); - case 4: - get_value_from_register(ctx, param->val+24, param->reg_nums[3]); - case 3: - get_value_from_register(ctx, param->val+16, param->reg_nums[2]); - case 2: - get_value_from_register(ctx, param->val+8, param->reg_nums[1]); - case 1: - get_value_from_register(ctx, param->val, param->reg_nums[0]); + case 6: + get_value_from_register(ctx, param->val+40, param->reg_nums[5]); + case 5: + get_value_from_register(ctx, param->val+32, param->reg_nums[4]); + case 4: + get_value_from_register(ctx, param->val+24, param->reg_nums[3]); + case 3: + get_value_from_register(ctx, param->val+16, param->reg_nums[2]); + case 2: + get_value_from_register(ctx, param->val+8, param->reg_nums[1]); + case 1: + get_value_from_register(ctx, param->val, param->reg_nums[0]); } return 0; } @@ -142,37 +141,17 @@ int parse_param(struct pt_regs *ctx, function_parameter_t *param) { __always_inline int get_goroutine_id(function_parameter_list_t *parsed_args) { - // Since eBPF programs have such strict stack requirements - // me must implement our own heap using a ringbuffer. - // Reserve some memory in our "heap" for the task_struct. struct task_struct *task; - task = bpf_ringbuf_reserve(&heap, sizeof(struct task_struct), 0); - if (!task) { - return 0; - } + size_t g_addr; + __u64 goid; // Get the current task. - __u64 task_ptr = bpf_get_current_task(); - if (!task_ptr) - { - bpf_ringbuf_discard(task, 0); - return 0; - } - // The bpf_get_current_task helper returns us the address of the task_struct in - // kernel memory. Use the bpf_probe_read_kernel helper to read the struct out of - // kernel memory. - bpf_probe_read_kernel(task, sizeof(struct task_struct), (void*)(task_ptr)); - + task = (struct task_struct *)bpf_get_current_task(); // Get the Goroutine ID which is stored in thread local storage. - __u64 goid; - size_t g_addr; - bpf_probe_read_user(&g_addr, sizeof(void *), (void*)(task->thread.fsbase+parsed_args->g_addr_offset)); + bpf_probe_read_user(&g_addr, sizeof(void *), (void*)(BPF_CORE_READ(task, thread.fsbase)+parsed_args->g_addr_offset)); bpf_probe_read_user(&goid, sizeof(void *), (void*)(g_addr+parsed_args->goid_offset)); parsed_args->goroutine_id = goid; - // Free back up the memory we reserved for the task_struct. - bpf_ringbuf_discard(task, 0); - return 1; } @@ -181,18 +160,18 @@ void parse_params(struct pt_regs *ctx, unsigned int n_params, function_parameter // Since we cannot loop in eBPF programs let's take adavantage of the // fact that in C switch cases will pass through automatically. switch (n_params) { - case 6: - parse_param(ctx, ¶ms[5]); - case 5: - parse_param(ctx, ¶ms[4]); - case 4: - parse_param(ctx, ¶ms[3]); - case 3: - parse_param(ctx, ¶ms[2]); - case 2: - parse_param(ctx, ¶ms[1]); - case 1: - parse_param(ctx, ¶ms[0]); + case 6: + parse_param(ctx, ¶ms[5]); + case 5: + parse_param(ctx, ¶ms[4]); + case 4: + parse_param(ctx, ¶ms[3]); + case 3: + parse_param(ctx, ¶ms[2]); + case 2: + parse_param(ctx, ¶ms[1]); + case 1: + parse_param(ctx, ¶ms[0]); } } @@ -207,7 +186,7 @@ int uprobe__dlv_trace(struct pt_regs *ctx) { return 1; } - parsed_args = bpf_ringbuf_reserve(&events, sizeof(function_parameter_list_t), 0); + parsed_args = bpf_ringbuf_reserve(&events, sizeof(function_parameter_list_t), 0); if (!parsed_args) { return 1; } @@ -220,8 +199,8 @@ int uprobe__dlv_trace(struct pt_regs *ctx) { parsed_args->n_parameters = args->n_parameters; parsed_args->n_ret_parameters = args->n_ret_parameters; parsed_args->is_ret = args->is_ret; - memcpy(parsed_args->params, args->params, sizeof(args->params)); - memcpy(parsed_args->ret_params, args->ret_params, sizeof(args->ret_params)); + __builtin_memcpy(parsed_args->params, args->params, sizeof(args->params)); + __builtin_memcpy(parsed_args->ret_params, args->ret_params, sizeof(args->ret_params)); if (!get_goroutine_id(parsed_args)) { bpf_ringbuf_discard(parsed_args, 0); diff --git a/pkg/proc/internal/ebpf/testhelper/testhelper.go b/pkg/proc/internal/ebpf/testhelper/testhelper.go index 2441990da2..3aef49f5d2 100644 --- a/pkg/proc/internal/ebpf/testhelper/testhelper.go +++ b/pkg/proc/internal/ebpf/testhelper/testhelper.go @@ -3,6 +3,7 @@ package testhelper +// #include // #include "../bpf/include/function_vals.bpf.h" import "C" diff --git a/pkg/proc/internal/ebpf/trace_bpfel_x86.go b/pkg/proc/internal/ebpf/trace_bpfel_x86.go index 61675e26c1..00880e507e 100644 --- a/pkg/proc/internal/ebpf/trace_bpfel_x86.go +++ b/pkg/proc/internal/ebpf/trace_bpfel_x86.go @@ -64,7 +64,6 @@ type traceProgramSpecs struct { type traceMapSpecs struct { ArgMap *ebpf.MapSpec `ebpf:"arg_map"` Events *ebpf.MapSpec `ebpf:"events"` - Heap *ebpf.MapSpec `ebpf:"heap"` } // traceObjects contains all objects after they have been loaded into the kernel. @@ -88,14 +87,12 @@ func (o *traceObjects) Close() error { type traceMaps struct { ArgMap *ebpf.Map `ebpf:"arg_map"` Events *ebpf.Map `ebpf:"events"` - Heap *ebpf.Map `ebpf:"heap"` } func (m *traceMaps) Close() error { return _TraceClose( m.ArgMap, m.Events, - m.Heap, ) } diff --git a/pkg/proc/internal/ebpf/trace_bpfel_x86.o b/pkg/proc/internal/ebpf/trace_bpfel_x86.o index cadd890231..5f8c720389 100644 Binary files a/pkg/proc/internal/ebpf/trace_bpfel_x86.o and b/pkg/proc/internal/ebpf/trace_bpfel_x86.o differ