Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ $(error Unsupported architecture: $(TARGET_ARCH))
endif

export TARGET_ARCH
export CGO_ENABLED = 1
export CGO_ENABLED = 0
export GOARCH = $(TARGET_ARCH)
export CC = $(ARCH_PREFIX)-linux-gnu-gcc
export OBJCOPY = $(ARCH_PREFIX)-linux-gnu-objcopy
Expand Down Expand Up @@ -103,7 +103,8 @@ vanity-import-fix: $(PORTO)
@porto --include-internal -w .

test: generate ebpf test-deps
go test $(GO_FLAGS) -tags $(GO_TAGS) ./...
# tools/coredump tests build ebpf C-code using CGO to test it against coredumps
CGO_ENABLED=1 go test $(GO_FLAGS) -tags $(GO_TAGS) ./...
Comment thread
fabled marked this conversation as resolved.

# This target isn't called from CI, it doesn't work for cross compile (ie TARGET_ARCH=arm64 on
# amd64) and the CI kernel tests run them already. Useful for local testing.
Expand All @@ -130,7 +131,7 @@ support/golbls_1_24.test: ./interpreter/golabels/test/main.go
CGO_ENABLED=0 GOTOOLCHAIN=go1.24.1 go build -tags $(GO_TAGS),nocgo -o $@ $<

support/golbls_cgo.test: ./interpreter/golabels/test/main-cgo.go
GOTOOLCHAIN=go1.24.1 go build -ldflags '-extldflags "-static"' -tags $(GO_TAGS),usecgo -o $@ $<
CGO_ENABLED=1 GOTOOLCHAIN=go1.24.1 go build -ldflags '-extldflags "-static"' -tags $(GO_TAGS),usecgo -o $@ $<

integration-test-binaries: generate ebpf rust-components support/golbls_1_23.test support/golbls_1_24.test support/golbls_cgo.test
$(foreach test_name, $(TEST_INTEGRATION_BINARY_DIRS), \
Expand Down
8 changes: 3 additions & 5 deletions interpreter/golabels/golabels.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ import (
"go.opentelemetry.io/ebpf-profiler/interpreter"
"go.opentelemetry.io/ebpf-profiler/libpf"
"go.opentelemetry.io/ebpf-profiler/remotememory"
"go.opentelemetry.io/ebpf-profiler/support"
)

// #include "../../support/ebpf/types.h"
import "C"

type data struct {
goVersion string
offsets C.GoLabelsOffsets
offsets support.GoLabelsOffsets
interpreter.InstanceStubs
}

Expand Down Expand Up @@ -64,7 +62,7 @@ func Loader(_ interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interprete
if err != nil {
return nil, fmt.Errorf("failed to extract TLS offset: %w", err)
}
offsets.tls_offset = C.s32(tlsOffset)
offsets.Tls_offset = tlsOffset

return &data{
goVersion: goVersion,
Expand Down
34 changes: 17 additions & 17 deletions interpreter/golabels/runtime_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,49 @@

package golabels // import "go.opentelemetry.io/ebpf-profiler/interpreter/golabels"

// #include "../../support/ebpf/types.h"
import "C"
import (
"go/version"

"go.opentelemetry.io/ebpf-profiler/support"
)

// Offsets come from DWARF debug information, use tools/gooffsets to extract them.
// However since DWARF information can be stripped we record them here.
// TODO: Should we look for DWARF information to support new versions
// automatically when available?
func getOffsets(vers string) C.GoLabelsOffsets {
offsets := C.GoLabelsOffsets{
func getOffsets(vers string) support.GoLabelsOffsets {
offsets := support.GoLabelsOffsets{
// https://github.com/golang/go/blob/80e2e474b8d9124d03b744f/src/runtime/runtime2.go#L410
m_offset: 48,
M_offset: 48,
// https://github.com/golang/go/blob/80e2e474b8d9124d03b744f/src/runtime/runtime2.go#L541
curg: 192,
Curg: 192,
// https://github.com/golang/go/blob/80e2e474b8d9124d03b744f/src/runtime/runtime2.go#L483
labels: 0,
Labels: 0,
// https://github.com/golang/go/blob/6885bad7dd86880be6929c0/src/runtime/map.go#L112
hmap_count: 0,
Hmap_count: 0,
// https://github.com/golang/go/blob/6885bad7dd86880be6929c0/src/runtime/map.go#L114
hmap_log2_bucket_count: 0,
Hmap_log2_bucket_count: 0,
// https://github.com/golang/go/blob/6885bad7dd86880be6929c0/src/runtime/map.go#L118
hmap_buckets: 0,
Hmap_buckets: 0,
}

// Version enforcement takes place in the Loader function.
if version.Compare(vers, "go1.24") >= 0 {
offsets.labels = 352
offsets.Labels = 352
return offsets
}

// These are the same for all versions but we have to leave them zero for 1.24+ detection.
offsets.hmap_log2_bucket_count = 9
offsets.hmap_buckets = 16
offsets.Hmap_log2_bucket_count = 9
offsets.Hmap_buckets = 16
if version.Compare(vers, "go1.23") >= 0 {
offsets.labels = 352
offsets.Labels = 352
} else if version.Compare(vers, "go1.21") >= 0 {
offsets.labels = 344
offsets.Labels = 344
} else if version.Compare(vers, "go1.17") >= 0 {
offsets.labels = 360
offsets.Labels = 360
} else {
offsets.labels = 344
offsets.Labels = 344
}
return offsets
}
61 changes: 27 additions & 34 deletions interpreter/hotspot/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ import (
"go.opentelemetry.io/ebpf-profiler/util"
)

// #include "../../support/ebpf/types.h"
// #include "../../support/ebpf/frametypes.h"
import "C"

// heapRange contains info for an individual heap.
type heapRange struct {
codeStart, codeEnd libpf.Address
Expand Down Expand Up @@ -237,9 +233,9 @@ func (d *hotspotInstance) getPoolSymbol(addr libpf.Address, ndx uint16) libpf.St

// getStubNameID read the stub name from the code blob at given address and generates a ID.
func (d *hotspotInstance) getStubNameID(symbolReporter reporter.SymbolReporter, ripOrBci uint32,
addr libpf.Address, _ uint32) (libpf.AddressOrLineno, error) {
addr libpf.Address, _ uint32) libpf.AddressOrLineno {
if value, ok := d.addrToStubNameID.Get(addr); ok {
return value, nil
return value
}
vms := &d.d.Get().vmStructs
constStubNameAddr := d.rm.Ptr(addr + libpf.Address(vms.CodeBlob.Name))
Expand All @@ -263,7 +259,7 @@ func (d *hotspotInstance) getStubNameID(symbolReporter reporter.SymbolReporter,
})
d.addrToStubNameID.Add(addr, stubID)

return stubID, nil
return stubID
}

// getMethod reads and returns the interesting data from "class Method" at given address
Expand Down Expand Up @@ -745,31 +741,31 @@ func (d *hotspotInstance) populateMainMappings(vmd *hotspotVMData,

// Set up the main eBPF info structure.
vms := &vmd.vmStructs
procInfo := C.HotspotProcInfo{
nmethod_deopt_offset: C.u16(vms.Nmethod.DeoptimizeOffset),
nmethod_compileid: C.u16(vms.Nmethod.CompileID),
nmethod_orig_pc_offset: C.u16(vms.Nmethod.OrigPcOffset),
codeblob_name: C.u8(vms.CodeBlob.Name),
codeblob_codestart: C.u8(vms.CodeBlob.CodeBegin),
codeblob_codeend: C.u8(vms.CodeBlob.CodeEnd),
codeblob_framecomplete: C.u8(vms.CodeBlob.FrameCompleteOffset),
codeblob_framesize: C.u8(vms.CodeBlob.FrameSize),
cmethod_size: C.u8(vms.ConstMethod.Sizeof),
heapblock_size: C.u8(vms.HeapBlock.Sizeof),
method_constmethod: C.u8(vms.Method.ConstMethod),
jvm_version: C.u8(vmd.version >> 24),
segment_shift: C.u8(heap.segmentShift),
nmethod_uses_offsets: C.u8(vmd.nmethodUsesOffsets),
procInfo := support.HotspotProcInfo{
Nmethod_deopt_offset: uint16(vms.Nmethod.DeoptimizeOffset),
Nmethod_compileid: uint16(vms.Nmethod.CompileID),
Nmethod_orig_pc_offset: uint16(vms.Nmethod.OrigPcOffset),
Codeblob_name: uint8(vms.CodeBlob.Name),
Codeblob_codestart: uint8(vms.CodeBlob.CodeBegin),
Codeblob_codeend: uint8(vms.CodeBlob.CodeEnd),
Codeblob_framecomplete: uint8(vms.CodeBlob.FrameCompleteOffset),
Codeblob_framesize: uint8(vms.CodeBlob.FrameSize),
Cmethod_size: uint8(vms.ConstMethod.Sizeof),
Heapblock_size: uint8(vms.HeapBlock.Sizeof),
Method_constmethod: uint8(vms.Method.ConstMethod),
Jvm_version: uint8(vmd.version >> 24),
Segment_shift: uint8(heap.segmentShift),
Nmethod_uses_offsets: vmd.nmethodUsesOffsets,
}

if vms.CodeCache.LowBound == 0 {
// JDK-8 has only one heap, use its bounds
procInfo.codecache_start = C.u64(heap.ranges[0].codeStart)
procInfo.codecache_end = C.u64(heap.ranges[0].codeEnd)
procInfo.Codecache_start = uint64(heap.ranges[0].codeStart)
procInfo.Codecache_end = uint64(heap.ranges[0].codeEnd)
} else {
// JDK9+ the VM tracks it separately
procInfo.codecache_start = C.u64(d.rm.Ptr(vms.CodeCache.LowBound + d.bias))
procInfo.codecache_end = C.u64(d.rm.Ptr(vms.CodeCache.HighBound + d.bias))
procInfo.Codecache_start = uint64(d.rm.Ptr(vms.CodeCache.LowBound + d.bias))
procInfo.Codecache_end = uint64(d.rm.Ptr(vms.CodeCache.HighBound + d.bias))
}

if err = ebpf.UpdateProcData(libpf.HotSpot, pid, unsafe.Pointer(&procInfo)); err != nil {
Expand Down Expand Up @@ -875,22 +871,19 @@ func (d *hotspotInstance) Symbolize(symbolReporter reporter.SymbolReporter,
sfCounter := successfailurecounter.New(&d.successCount, &d.failCount)
defer sfCounter.DefaultToFailure()

switch subtype {
case C.FRAME_HOTSPOT_STUB, C.FRAME_HOTSPOT_VTABLE:
switch uint8(subtype) {
case support.FrameHotspotStub, support.FrameHotspotVtable:
// These are stub frames that may or may not be interesting
// to be seen in the trace.
stubID, err1 := d.getStubNameID(symbolReporter, ripOrBci, ptr, ptrCheck)
if err1 != nil {
return err
}
stubID := d.getStubNameID(symbolReporter, ripOrBci, ptr, ptrCheck)
trace.AppendFrame(libpf.HotSpotFrame, hotspotStubsFileID, stubID)
case C.FRAME_HOTSPOT_INTERPRETER:
case support.FrameHotspotInterpreter:
method, err1 := d.getMethod(ptr, ptrCheck)
if err1 != nil {
return err1
}
method.symbolize(symbolReporter, ripOrBci, d, trace)
case C.FRAME_HOTSPOT_NATIVE:
case support.FrameHotspotNative:
jitinfo, err1 := d.getJITInfo(ptr, ptrCheck)
if err1 != nil {
return err1
Expand Down
Loading