Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from kubescape/feature/integ
Browse files Browse the repository at this point in the history
Feature/integ
amitschendel authored Oct 20, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 64c3f2c + f18529a commit 20d4985
Showing 23 changed files with 166 additions and 199 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
.cache
/.idea
/go
.vscode
ebpf-profiler
ci-kernels
ebpf-profiler
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"typeinfo": "cpp"
}
}
21 changes: 6 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -32,14 +32,6 @@ export GOARCH = $(TARGET_ARCH)
export CC = $(ARCH_PREFIX)gcc
export OBJCOPY = $(ARCH_PREFIX)objcopy

# Add EXTERNAL flag support
ifdef EXTERNAL
export EXTERNAL
GO_TAGS := osusergo,netgo,external_trigger
else
GO_TAGS := osusergo,netgo
endif

BRANCH = $(shell git rev-parse --abbrev-ref HEAD | tr -d '-' | tr '[:upper:]' '[:lower:]')
COMMIT_SHORT_SHA = $(shell git rev-parse --short=8 HEAD)

@@ -52,11 +44,11 @@ LDFLAGS := -X go.opentelemetry.io/ebpf-profiler/vc.version=$(VERSION) \
-X go.opentelemetry.io/ebpf-profiler/vc.buildTimestamp=$(BUILD_TIMESTAMP) \
-extldflags=-static


GO_FLAGS := -buildvcs=false -ldflags="$(LDFLAGS)" -tags $(GO_TAGS)

GO_TAGS := osusergo,netgo
EBPF_FLAGS :=

GO_FLAGS := -buildvcs=false -ldflags="$(LDFLAGS)"

MAKEFLAGS += -j$(shell nproc)

all: ebpf-profiler
@@ -77,8 +69,7 @@ generate:
go generate ./...

ebpf:
$(MAKE) $(EBPF_FLAGS) -j$(shell nproc) -C support/ebpf EXTERNAL=external
$(MAKE) $(EBPF_FLAGS) -j$(shell nproc) -C support/ebpf
$(MAKE) $(EBPF_FLAGS) -C support/ebpf

ebpf-profiler: generate ebpf
go build $(GO_FLAGS) -tags $(GO_TAGS)
@@ -129,7 +120,7 @@ docker-image:

agent:
docker run -v "$$PWD":/agent -it --rm --user $(shell id -u):$(shell id -g) profiling-agent \
"make TARGET_ARCH=$(TARGET_ARCH) VERSION=$(VERSION) REVISION=$(REVISION) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) $(if $(EXTERNAL),EXTERNAL=external)"
"make TARGET_ARCH=$(TARGET_ARCH) VERSION=$(VERSION) REVISION=$(REVISION) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP)"

debug-agent:
docker run -v "$$PWD":/agent -it --rm --user $(shell id -u):$(shell id -g) profiling-agent \
@@ -141,4 +132,4 @@ legal:
@./legal/add-non-go.sh legal/non-go-dependencies.json LICENSES

codespell:
@codespell
@codespell
29 changes: 4 additions & 25 deletions support/ebpf/Makefile
Original file line number Diff line number Diff line change
@@ -5,13 +5,6 @@ LLC ?= llc-16

DEBUG_FLAGS = -DOPTI_DEBUG -g

# Check if EXTERNAL flag is set
ifdef EXTERNAL
EXTERNAL_FLAG = -DEXTERNAL_TRIGGER
else
EXTERNAL_FLAG =
endif

# Detect native architecture and translate to GOARCH.
NATIVE_ARCH := $(shell uname -m)
ifeq ($(NATIVE_ARCH),x86_64)
@@ -28,11 +21,7 @@ TARGET_ARCH ?= $(NATIVE_ARCH)
# Valid values: release, debug
BUILD_TYPE ?= release

ifdef EXTERNAL
TRACER_NAME ?= tracer.ebpf.$(BUILD_TYPE).$(EXTERNAL).$(TARGET_ARCH)
else
TRACER_NAME ?= tracer.ebpf.$(BUILD_TYPE).$(TARGET_ARCH)
endif
TRACER_NAME ?= tracer.ebpf.$(BUILD_TYPE).$(TARGET_ARCH)

ifeq ($(TARGET_ARCH),arm64)
TARGET_FLAGS = -target aarch64-linux-gnu
@@ -55,15 +44,10 @@ FLAGS=$(TARGET_FLAGS) \
-Wno-unused-label \
-Wno-unused-parameter \
-Wno-sign-compare \
-fno-stack-protector \
$(EXTERNAL_FLAG)
-fno-stack-protector

SRCS := $(wildcard *.ebpf.c)
ifdef EXTERNAL
OBJS := $(SRCS:.c=.$(BUILD_TYPE).$(EXTERNAL).$(TARGET_ARCH).o)
else
OBJS := $(SRCS:.c=.$(BUILD_TYPE).$(TARGET_ARCH).o)
endif
OBJS := $(SRCS:.c=.$(BUILD_TYPE).$(TARGET_ARCH).o)

.DEFAULT_GOAL := all

@@ -89,13 +73,8 @@ errors.h: ../../tools/errors-codegen/errors.json

%.ebpf.c: errors.h ;

ifdef EXTERNAL
%.ebpf.$(BUILD_TYPE).$(EXTERNAL).$(TARGET_ARCH).o: %.ebpf.c
$(BPF_CLANG) $(FLAGS) -o $@
else
%.ebpf.$(BUILD_TYPE).$(TARGET_ARCH).o: %.ebpf.c
$(BPF_CLANG) $(FLAGS) -o $@
endif

$(TRACER_NAME): $(OBJS)
$(BPF_LINK) $^ -o - | $(LLC) -march=bpf -mcpu=v2 -filetype=obj -o $@
@@ -108,4 +87,4 @@ bloatcheck: $(TRACER_NAME)
python3 bloat-o-meter $(TRACER_NAME).baseline $(TRACER_NAME)

clean:
rm -f *.o
rm -f *.o
8 changes: 5 additions & 3 deletions support/ebpf/dotnet_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -245,8 +245,8 @@ ErrorCode unwind_one_dotnet_frame(PerCPURecord *record, DotnetProcInfo *vi, bool
// unwind_dotnet is the entry point for tracing when invoked from the native tracer
// or interpreter dispatcher. It does not reset the trace object and will append the
// dotnet stack frames to the trace object for the current CPU.
BPF_PROBE(unwind_dotnet)
int unwind_dotnet(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_dotnet(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record) {
@@ -287,7 +287,9 @@ int unwind_dotnet(struct pt_regs *ctx)

exit:
record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
DEBUG_PRINT("dotnet: tail call for next frame unwinder (%d) failed", unwinder);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_dotnet, unwind_dotnet);
3 changes: 2 additions & 1 deletion support/ebpf/extmaps.h
Original file line number Diff line number Diff line change
@@ -6,7 +6,8 @@
#include "bpf_map.h"

// References to map definitions in *.ebpf.c.
extern bpf_map_def progs;
extern bpf_map_def perf_progs;
extern bpf_map_def kprobe_progs;
extern bpf_map_def per_cpu_records;
extern bpf_map_def pid_page_to_mapping_info;
extern bpf_map_def metrics;
17 changes: 12 additions & 5 deletions support/ebpf/helpers.h
Original file line number Diff line number Diff line change
@@ -4,10 +4,17 @@
#define OPTI_HELPERS_H

// Macros for BPF program type and context handling.
#ifdef EXTERNAL_TRIGGER
#define BPF_PROBE(name) SEC("kprobe/"#name)
#else
#define BPF_PROBE(name) SEC("perf_event/"#name)
#endif
#define DEFINE_DUAL_PROGRAM(name, func) \
SEC("perf_event/" #name) \
int name##_perf(struct pt_regs *ctx) \
{ \
return func(ctx, &perf_progs); \
} \
\
SEC("kprobe/" #name) \
int name##_kprobe(struct pt_regs *ctx) \
{ \
return func(ctx, &kprobe_progs); \
}

#endif // OPTI_HELPERS_H
8 changes: 5 additions & 3 deletions support/ebpf/hotspot_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -891,8 +891,8 @@ static ErrorCode hotspot_unwind_one_frame(PerCPURecord *record, HotspotProcInfo
// unwind_hotspot is the entry point for tracing when invoked from the native tracer
// and it recursive unwinds all HotSpot frames and then jumps back to unwind further
// native frames that follow.
BPF_PROBE(unwind_hotspot)
int unwind_hotspot(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_hotspot(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -925,7 +925,9 @@ int unwind_hotspot(struct pt_regs *ctx)
}

record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
DEBUG_PRINT("jvm: tail call for next frame unwinder (%d) failed", unwinder);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_hotspot, unwind_hotspot);
19 changes: 14 additions & 5 deletions support/ebpf/interpreter_dispatcher.ebpf.c
Original file line number Diff line number Diff line change
@@ -26,8 +26,16 @@ bpf_map_def SEC("maps") metrics = {
.max_entries = metricID_Max,
};

// progs maps from a program ID to an eBPF program
bpf_map_def SEC("maps") progs = {
// perf progs maps from a program ID to an eBPF program
bpf_map_def SEC("maps") perf_progs = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u32),
.max_entries = NUM_TRACER_PROGS,
};

// kprobe progs maps from a program ID to an eBPF program
bpf_map_def SEC("maps") kprobe_progs = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u32),
@@ -172,9 +180,8 @@ void maybe_add_apm_info(Trace *trace) {
DEBUG_PRINT("APM transaction ID: %016llX, flags: 0x%02X",
trace->apm_transaction_id.as_int, corr_buf.trace_flags);
}

BPF_PROBE(unwind_stop)
int unwind_stop(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_stop(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -241,6 +248,8 @@ int unwind_stop(struct pt_regs *ctx)
return 0;
}

DEFINE_DUAL_PROGRAM(unwind_stop, unwind_stop);

char _license[] SEC("license") = "GPL";
// this number will be interpreted by the elf loader
// to set the current running kernel version
26 changes: 17 additions & 9 deletions support/ebpf/native_stack_trace.ebpf.c
Original file line number Diff line number Diff line change
@@ -748,8 +748,8 @@ static inline ErrorCode get_usermode_regs(struct pt_regs *ctx,

#endif

BPF_PROBE(unwind_native)
int unwind_native(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_native(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -796,13 +796,15 @@ int unwind_native(struct pt_regs *ctx)
// Tail call needed for recursion, switching to interpreter unwinder, or reporting
// trace due to end-of-trace or error. The unwinder program index is set accordingly.
record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
DEBUG_PRINT("bpf_tail call failed for %d in unwind_native", unwinder);
return -1;
}

static inline
int collect_trace(struct pt_regs *ctx) {
DEFINE_DUAL_PROGRAM(unwind_native, unwind_native);

static inline __attribute__((__always_inline__))
int collect_trace(struct pt_regs *ctx, bpf_map_def *prog_map) {
// Get the PID and TGID register.
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;
@@ -854,13 +856,19 @@ int collect_trace(struct pt_regs *ctx) {

exit:
record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
DEBUG_PRINT("bpf_tail call failed for %d in native_tracer_entry", unwinder);
return -1;
}

BPF_PROBE(native_tracer_entry)
int native_tracer_entry(struct bpf_perf_event_data *ctx)
SEC("perf_event/native_tracer_entry")
int native_tracer_entry_perf(struct bpf_perf_event_data *ctx)
{
return collect_trace((struct pt_regs*) &ctx->regs, &perf_progs);
}

SEC("kprobe/native_tracer_entry")
int native_tracer_entry_kprobe(struct pt_regs *ctx)
{
return collect_trace((struct pt_regs*) &ctx->regs);
return collect_trace(ctx, &kprobe_progs);
}
8 changes: 5 additions & 3 deletions support/ebpf/perl_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -357,8 +357,8 @@ int walk_perl_stack(PerCPURecord *record, const PerlProcInfo *perlinfo) {
// unwind_perl is the entry point for tracing when invoked from the native tracer
// or interpreter dispatcher. It does not reset the trace object and will append the
// Perl stack frames to the trace object for the current CPU.
BPF_PROBE(unwind_perl)
int unwind_perl(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_perl(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record) {
@@ -425,6 +425,8 @@ int unwind_perl(struct pt_regs *ctx)
unwinder = walk_perl_stack(record, perlinfo);

exit:
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_perl, unwind_perl);
8 changes: 5 additions & 3 deletions support/ebpf/php_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -183,8 +183,8 @@ int walk_php_stack(PerCPURecord *record, PHPProcInfo *phpinfo, bool is_jitted) {
return unwinder;
}

BPF_PROBE(unwind_php)
int unwind_php(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_php(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -238,6 +238,8 @@ int unwind_php(struct pt_regs *ctx)
unwinder = walk_php_stack(record, phpinfo, is_jitted);

exit:
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_php, unwind_php)
8 changes: 5 additions & 3 deletions support/ebpf/python_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -277,8 +277,8 @@ ErrorCode get_PyFrame(const PyProcInfo *pyinfo, void **frame) {
// unwind_python is the entry point for tracing when invoked from the native tracer
// or interpreter dispatcher. It does not reset the trace object and will append the
// Python stack frames to the trace object for the current CPU.
BPF_PROBE(unwind_python)
int unwind_python(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_python(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -317,6 +317,8 @@ int unwind_python(struct pt_regs *ctx)

exit:
record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_python, unwind_python);
9 changes: 5 additions & 4 deletions support/ebpf/ruby_tracer.ebpf.c
Original file line number Diff line number Diff line change
@@ -216,9 +216,8 @@ ErrorCode walk_ruby_stack(PerCPURecord *record, const RubyProcInfo *rubyinfo,

return ERR_OK;
}

BPF_PROBE(unwind_ruby)
int unwind_ruby(struct pt_regs *ctx)
static inline __attribute__((__always_inline__))
int unwind_ruby(struct pt_regs *ctx, bpf_map_def *prog_map)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
@@ -272,6 +271,8 @@ int unwind_ruby(struct pt_regs *ctx)

exit:
record->state.unwind_error = error;
tail_call(ctx, unwinder);
tail_call(ctx, unwinder, prog_map);
return -1;
}

DEFINE_DUAL_PROGRAM(unwind_ruby, unwind_ruby);
Loading

0 comments on commit 20d4985

Please sign in to comment.