Skip to content

Commit

Permalink
Merge pull request #2 from kubescape/feature/integ
Browse files Browse the repository at this point in the history
Feature/integ
  • Loading branch information
amitschendel authored Oct 15, 2024
2 parents 13a01a8 + aa029f4 commit c74f1fd
Show file tree
Hide file tree
Showing 19 changed files with 126 additions and 53 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/go
ebpf-profiler
ci-kernels
ebpf-profiler
18 changes: 13 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ 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)

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

GO_TAGS := osusergo,netgo
EBPF_FLAGS :=

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

EBPF_FLAGS :=

MAKEFLAGS += -j$(shell nproc)

Expand All @@ -69,7 +77,7 @@ generate:
go generate ./...

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

ebpf-profiler: generate ebpf
go build $(GO_FLAGS) -tags $(GO_TAGS)
Expand Down Expand Up @@ -120,7 +128,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)"
"make TARGET_ARCH=$(TARGET_ARCH) VERSION=$(VERSION) REVISION=$(REVISION) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) $(if $(EXTERNAL),EXTERNAL=1)"

debug-agent:
docker run -v "$$PWD":/agent -it --rm --user $(shell id -u):$(shell id -g) profiling-agent \
Expand Down
14 changes: 9 additions & 5 deletions cli_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ const (
var (
noKernelVersionCheckHelp = "Disable checking kernel version for eBPF support. " +
"Use at your own risk, to run the agent on older kernels with backported eBPF features."
copyrightHelp = "Show copyright and short license text."
collAgentAddrHelp = "The collection agent address in the format of host:port."
verboseModeHelp = "Enable verbose logging and debugging capabilities."
tracersHelp = "Comma-separated list of interpreter tracers to include."
mapScaleFactorHelp = fmt.Sprintf("Scaling factor for eBPF map sizes. "+
copyrightHelp = "Show copyright and short license text."
collAgentAddrHelp = "The collection agent address in the format of host:port."
verboseModeHelp = "Enable verbose logging and debugging capabilities."
tracersHelp = "Comma-separated list of interpreter tracers to include."
externallyManagedHelp = "Agent is externally managed."
mapScaleFactorHelp = fmt.Sprintf("Scaling factor for eBPF map sizes. "+
"Every increase by 1 doubles the map size. Increase if you see eBPF map size errors. "+
"Default is %d corresponding to 4GB of executable address space, max is %d.",
defaultArgMapScaleFactor, maxArgMapScaleFactor)
Expand Down Expand Up @@ -81,6 +82,7 @@ type arguments struct {
samplesPerSecond int
sendErrorFrames bool
tracers string
externallyManaged bool
verboseMode bool
version bool

Expand Down Expand Up @@ -134,6 +136,8 @@ func parseArgs() (*arguments, error) {
fs.StringVar(&args.tracers, "t", "all", "Shorthand for -tracers.")
fs.StringVar(&args.tracers, "tracers", "all", tracersHelp)

fs.BoolVar(&args.externallyManaged, "externally-managed", false, externallyManagedHelp)

fs.BoolVar(&args.verboseMode, "v", false, "Shorthand for -verbose.")
fs.BoolVar(&args.verboseMode, "verbose", false, verboseModeHelp)
fs.BoolVar(&args.version, "version", false, versionHelp)
Expand Down
29 changes: 18 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,25 @@ func mainWithExitCode() exitCode {
metrics.Add(metrics.IDProcPIDStartupMs, metrics.MetricValue(time.Since(now).Milliseconds()))
log.Debug("Completed initial PID listing")

// Attach our tracer to the perf event
if err := trc.AttachTracer(); err != nil {
return failure("Failed to attach to perf event: %v", err)
}
log.Info("Attached tracer program")

if args.probabilisticThreshold < tracer.ProbabilisticThresholdMax {
trc.StartProbabilisticProfiling(mainCtx)
log.Printf("Enabled probabilistic profiling")
if args.externallyManaged {
_, err := trc.GetNativeTracerEntry()
if err != nil {
return failure("Failed to get native tracer entry: %v", err)
}
} else {
if err := trc.EnableProfiling(); err != nil {
return failure("Failed to enable perf events: %v", err)
// Attach our tracer to the perf event
if err := trc.AttachTracer(); err != nil {
return failure("Failed to attach to perf event: %v", err)
}
log.Info("Attached tracer program")

if args.probabilisticThreshold < tracer.ProbabilisticThresholdMax {
trc.StartProbabilisticProfiling(mainCtx)
log.Printf("Enabled probabilistic profiling")
} else {
if err := trc.EnableProfiling(); err != nil {
return failure("Failed to enable perf events: %v", err)
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"

"golang.org/x/sys/unix"
Expand Down Expand Up @@ -62,7 +63,7 @@ func trimMappingPath(path string) string {
return path
}

func parseMappings(mapsFile io.Reader) ([]Mapping, error) {
func parseMappings(mapsFile io.Reader, pid libpf.PID) ([]Mapping, error) {
mappings := make([]Mapping, 0)
scanner := bufio.NewScanner(mapsFile)
buf := make([]byte, 512)
Expand Down Expand Up @@ -118,7 +119,8 @@ func parseMappings(mapsFile io.Reader) ([]Mapping, error) {
continue
}
} else {
path = trimMappingPath(path)
// This is needed to support running the profiler from whithin a container.
path = "/proc/" + strconv.Itoa(int(pid)) + "/root/" + trimMappingPath(path)
path = strings.Clone(path)
}

Expand Down Expand Up @@ -148,7 +150,7 @@ func (sp *systemProcess) GetMappings() ([]Mapping, error) {
}
defer mapsFile.Close()

mappings, err := parseMappings(mapsFile)
mappings, err := parseMappings(mapsFile, sp.pid)
if err == nil {
fileToMapping := make(map[string]*Mapping)
for idx := range mappings {
Expand Down
16 changes: 8 additions & 8 deletions process/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var testMappings = `55fe82710000-55fe8273c000 r--p 00000000 fd:01 1068432
7f63c8ebf000-7f63c8fef000 r-xp 0001c000 1fd:01 1075944 /tmp/usr_lib_x86_64-linux-gnu_libopensc.so.6.0.0`

func TestParseMappings(t *testing.T) {
mappings, err := parseMappings(strings.NewReader(testMappings))
mappings, err := parseMappings(strings.NewReader(testMappings), 1)
require.NoError(t, err)
assert.NotNil(t, mappings)

Expand All @@ -37,7 +37,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1068432,
Length: 0x2c000,
FileOffset: 0,
Path: "/tmp/usr_bin_seahorse",
Path: "/proc/1/root//tmp/usr_bin_seahorse",
},
{
Vaddr: 0x55fe8273c000,
Expand All @@ -46,7 +46,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1068432,
Length: 0x82000,
FileOffset: 0x2c000,
Path: "/tmp/usr_bin_seahorse",
Path: "/proc/1/root//tmp/usr_bin_seahorse",
},
{
Vaddr: 0x55fe827be000,
Expand All @@ -55,7 +55,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1068432,
Length: 0x78000,
FileOffset: 0xae000,
Path: "/tmp/usr_bin_seahorse",
Path: "/proc/1/root//tmp/usr_bin_seahorse",
},
{
Vaddr: 0x55fe82836000,
Expand All @@ -64,7 +64,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1068432,
Length: 0x7000,
FileOffset: 0x125000,
Path: "/tmp/usr_bin_seahorse",
Path: "/proc/1/root//tmp/usr_bin_seahorse",
},
{
Vaddr: 0x55fe8283d000,
Expand All @@ -73,7 +73,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1068432,
Length: 0x1000,
FileOffset: 0x12c000,
Path: "/tmp/usr_bin_seahorse",
Path: "/proc/1/root//tmp/usr_bin_seahorse",
},
{
Vaddr: 0x7f63c8c3e000,
Expand All @@ -82,7 +82,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1048922,
Length: 0x1A2000,
FileOffset: 544768,
Path: "/tmp/usr_lib_x86_64-linux-gnu_libcrypto.so.1.1",
Path: "/proc/1/root//tmp/usr_lib_x86_64-linux-gnu_libcrypto.so.1.1",
},
{
Vaddr: 0x7f63c8ebf000,
Expand All @@ -91,7 +91,7 @@ func TestParseMappings(t *testing.T) {
Inode: 1075944,
Length: 0x130000,
FileOffset: 114688,
Path: "/tmp/usr_lib_x86_64-linux-gnu_libopensc.so.6.0.0",
Path: "/proc/1/root//tmp/usr_lib_x86_64-linux-gnu_libopensc.so.6.0.0",
},
}
assert.Equal(t, expected, mappings)
Expand Down
10 changes: 9 additions & 1 deletion support/ebpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ 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)
Expand Down Expand Up @@ -44,7 +51,8 @@ FLAGS=$(TARGET_FLAGS) \
-Wno-unused-label \
-Wno-unused-parameter \
-Wno-sign-compare \
-fno-stack-protector
-fno-stack-protector \
$(EXTERNAL_FLAG)

SRCS := $(wildcard *.ebpf.c)
OBJS := $(SRCS:.c=.$(BUILD_TYPE).$(TARGET_ARCH).o)
Expand Down
6 changes: 4 additions & 2 deletions support/ebpf/dotnet_tracer.ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "bpfdefs.h"
#include "tracemgmt.h"
#include "types.h"
#include "helpers.h"

// The number of dotnet frames to unwind per frame-unwinding eBPF program.
#define DOTNET_FRAMES_PER_PROGRAM 5
Expand Down Expand Up @@ -244,8 +245,9 @@ 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.
SEC("perf_event/unwind_dotnet")
int unwind_dotnet(struct pt_regs *ctx) {
BPF_PROBE(unwind_dotnet)
int unwind_dotnet(struct pt_regs *ctx)
{
PerCPURecord *record = get_per_cpu_record();
if (!record) {
return -1;
Expand Down
13 changes: 13 additions & 0 deletions support/ebpf/helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Provide helpers for the eBPF code.

#ifndef OPTI_HELPERS_H
#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

#endif // OPTI_HELPERS_H
6 changes: 4 additions & 2 deletions support/ebpf/hotspot_tracer.ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "tracemgmt.h"
#include "types.h"
#include "errors.h"
#include "helpers.h"

// Information extracted from a JDK `CodeBlob` instance.
typedef struct CodeBlobInfo {
Expand Down Expand Up @@ -890,8 +891,9 @@ 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.
SEC("perf_event/unwind_hotspot")
int unwind_hotspot(struct pt_regs *ctx) {
BPF_PROBE(unwind_hotspot)
int unwind_hotspot(struct pt_regs *ctx)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
return -1;
Expand Down
6 changes: 4 additions & 2 deletions support/ebpf/interpreter_dispatcher.ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "types.h"
#include "tracemgmt.h"
#include "tsd.h"
#include "helpers.h"

// Begin shared maps

Expand Down Expand Up @@ -172,8 +173,9 @@ void maybe_add_apm_info(Trace *trace) {
trace->apm_transaction_id.as_int, corr_buf.trace_flags);
}

SEC("perf_event/unwind_stop")
int unwind_stop(struct pt_regs *ctx) {
BPF_PROBE(unwind_stop)
int unwind_stop(struct pt_regs *ctx)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
return -1;
Expand Down
11 changes: 7 additions & 4 deletions support/ebpf/native_stack_trace.ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "types.h"
#include "tracemgmt.h"
#include "stackdeltatypes.h"
#include "helpers.h"

#ifndef __USER32_CS
// defined in arch/x86/include/asm/segment.h
Expand Down Expand Up @@ -747,8 +748,9 @@ static inline ErrorCode get_usermode_regs(struct pt_regs *ctx,

#endif

SEC("perf_event/unwind_native")
int unwind_native(struct pt_regs *ctx) {
BPF_PROBE(unwind_native)
int unwind_native(struct pt_regs *ctx)
{
PerCPURecord *record = get_per_cpu_record();
if (!record)
return -1;
Expand Down Expand Up @@ -857,7 +859,8 @@ int collect_trace(struct pt_regs *ctx) {
return -1;
}

SEC("perf_event/native_tracer_entry")
int native_tracer_entry(struct bpf_perf_event_data *ctx) {
BPF_PROBE(native_tracer_entry)
int native_tracer_entry(struct bpf_perf_event_data *ctx)
{
return collect_trace((struct pt_regs*) &ctx->regs);
}
6 changes: 4 additions & 2 deletions support/ebpf/perl_tracer.ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "tracemgmt.h"
#include "types.h"
#include "tsd.h"
#include "helpers.h"

// The number of Perl frames to unwind per frame-unwinding eBPF program.
#define PERL_FRAMES_PER_PROGRAM 12
Expand Down Expand Up @@ -356,8 +357,9 @@ 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.
SEC("perf_event/unwind_perl")
int unwind_perl(struct pt_regs *ctx) {
BPF_PROBE(unwind_perl)
int unwind_perl(struct pt_regs *ctx)
{
PerCPURecord *record = get_per_cpu_record();
if (!record) {
return -1;
Expand Down
Loading

0 comments on commit c74f1fd

Please sign in to comment.