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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ test-deps:

TEST_INTEGRATION_BINARY_DIRS := tracer processmanager/ebpf support interpreter/golabels/integrationtests

pprof-execs: pprof_1_23 pprof_1_24 pprof_1_24_cgo
pprof-execs: pprof_1_23 pprof_1_24 pprof_1_24_cgo pprof_1_24_cgo_pie

pprof_1_23:
CGO_ENABLED=0 GOTOOLCHAIN=go1.23.7 go test -C ./interpreter/golabels/integrationtests/pprof -c -trimpath -tags $(GO_TAGS),nocgo,integration -o ./../$@
Expand All @@ -133,6 +133,9 @@ pprof_1_24:
pprof_1_24_cgo:
CGO_ENABLED=1 GOTOOLCHAIN=go1.24.6 go test -C ./interpreter/golabels/integrationtests/pprof -c -ldflags '-extldflags "-static"' -trimpath -tags $(GO_TAGS),withcgo,integration -o ./../$@

pprof_1_24_cgo_pie:
CGO_ENABLED=1 GOTOOLCHAIN=go1.24.6 go test -C ./interpreter/golabels/integrationtests/pprof -c -ldflags '-extldflags "-static"' -trimpath -buildmode=pie -tags $(GO_TAGS),withcgo,integration -o ./../$@

integration-test-binaries: generate ebpf pprof-execs
$(foreach test_name, $(TEST_INTEGRATION_BINARY_DIRS), \
(go test -ldflags='-extldflags=-static' -trimpath -c \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var (

//go:embed pprof_1_24_cgo
pprof_1_24_cgo []byte

//go:embed pprof_1_24_cgo_pie
pprof_1_24_cgo_pie []byte
)

type mockIntervals struct{}
Expand All @@ -51,9 +54,10 @@ func Test_Golabels(t *testing.T) {
tests := map[string]struct {
bin []byte
}{
"pprof_1_23": {bin: pprof_1_23},
"pprof_1_24": {bin: pprof_1_24},
"pprof_1_24_cgo": {bin: pprof_1_24_cgo},
"pprof_1_23": {bin: pprof_1_23},
"pprof_1_24": {bin: pprof_1_24},
"pprof_1_24_cgo": {bin: pprof_1_24_cgo},
"pprof_1_24_cgo_pie": {bin: pprof_1_24_cgo_pie},
}

for name, tc := range tests {
Expand Down
42 changes: 34 additions & 8 deletions interpreter/golabels/tls_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package golabels // import "go.opentelemetry.io/ebpf-profiler/interpreter/golabe

import (
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/ebpf-profiler/asm/amd"
e "go.opentelemetry.io/ebpf-profiler/asm/expression"
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
"go.opentelemetry.io/ebpf-profiler/nativeunwind/elfunwindinfo"
"golang.org/x/arch/x86/x86asm"
Expand All @@ -25,24 +27,48 @@ func extractTLSGOffset(f *pfelf.File) (int32, error) {

// Dump of assembler code for function runtime.stackcheck:
// 0x0000000000470080 <+0>: mov %fs:0xfffffffffffffff8,%rax
// Binaries built with -buildmode=pie have a different assembly code for stackcheck with 2 movs:
// 0x00000000007ec320 <+0>: mov $0xfffffffffffffff8,%rcx
// 0x00000000007ec327 <+7>: mov %fs:(%rcx),%rax
sym, err := pclntab.LookupSymbol("runtime.stackcheck")
if err != nil {
return 0, err
}
b, err := f.VirtualMemory(int64(sym.Address), 10, 10)
if err != nil {
return 0, err
}

i, err := x86asm.Decode(b, 64)
sz := int(min(sym.Size, 128))
code, err := f.VirtualMemory(int64(sym.Address), sz, sz)
if err != nil {
return 0, err
}
if i.Op == x86asm.MOV {
mem, ok := i.Args[1].(x86asm.Mem)
if ok {

offset := e.NewImmediateCapture("offset")
it := amd.NewInterpreterWithCode(code)
for {
op, err := it.Step()
if err != nil {
break
}
if op.Op != x86asm.MOV {
continue
}
mem, ok := op.Args[1].(x86asm.Mem)
if !ok || mem.Segment != x86asm.FS {
continue
}
// If the base is 0, it means the offset is directly in the register:
// 0x0000000000470080 <+0>: mov %fs:0xfffffffffffffff8,%rax
if mem.Base == 0 {
return int32(mem.Disp), nil
}
// Otherwise, the offset is in the register:
// 0x00000000007ec320 <+0>: mov $0xfffffffffffffff8,%rcx
// 0x00000000007ec327 <+7>: mov %fs:(%rcx),%rax
// Check if the register value was set with an immediate value in a previous instruction
// and if so, use that value as the offset.
actual := it.Regs.GetX86(mem.Base)
if actual.Match(offset) {
return int32(offset.CapturedValue()), nil
}
}
log.Warnf("Failed to decode stackcheck symbol, Go label collection might not work")
return -8, nil
Expand Down
26 changes: 25 additions & 1 deletion interpreter/golabels/tls_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import (
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/ebpf-profiler/armhelpers"
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
"golang.org/x/arch/arm64/arm64asm"
)
Expand All @@ -21,6 +22,17 @@
// 0x000000000007f270 <+16>: mov x27, #0x30 // #48
// 0x000000000007f274 <+20>: ldr x28, [x0, x27]
// 0x000000000007f278 <+24>: ret
//
// And, when compiled with -buildmode=pie:
//
// 0x00000000000c2290 <+0>: adrp x27, 0x2ca000 <runtime.itabTableInit+3072>
// 0x00000000000c2294 <+4>: ldrsb x0, [x27, #1766]
// 0x00000000000c2298 <+8>: cbz x0, 0xc22ac <runtime.load_g+28>
// 0x00000000000c229c <+12>: mrs x0, tpidr_el0
// 0x00000000000c22a0 <+16>: movz x27, #0x0, lsl #16
// 0x00000000000c22a4 <+20>: movk x27, #0x10
// 0x00000000000c22a8 <+24>: ldr x28, [x0, x27]
// 0x00000000000c22ac <+28>: ret
func extractTLSGOffset(f *pfelf.File) (int32, error) {
iscgo, err := f.IsCgoEnabled()
if err != nil || !iscgo {
Expand All @@ -47,11 +59,23 @@
if err != nil {
return 0, err
}
if i.Op == arm64asm.MOV {
switch i.Op {
case arm64asm.MOV:
imm, ok := i.Args[1].(arm64asm.Imm64)
if ok {
return int32(imm.Imm), nil
}
case arm64asm.MOVK:
// when compiled with -buildmode=pie, mov instruction is split into two instructions: movz and movk
// movz is used to zero the register and set bits 16-31, while movk is used to set the lower 16 bits:
// movz x27, #0x0, lsl #16
// movk x27, #0x10
// For now, we'll just decode the immediate value from the movk instruction since the one from the movz
// instruction seems to always be 0.
imm, ok := armhelpers.DecodeImmediate(i.Args[1])
if ok {
return int32(imm), nil
Comment thread Dismissed
}
}
}
log.Warnf("Failed to decode load_g symbol, Go label collection might not work with CGO frames")
Expand Down
Loading