diff --git a/processmanager/execinfomanager/manager.go b/processmanager/execinfomanager/manager.go index f1544d6bb..0fb9b5748 100644 --- a/processmanager/execinfomanager/manager.go +++ b/processmanager/execinfomanager/manager.go @@ -191,6 +191,13 @@ func (mgr *ExecutableInfoManager) AddOrIncRef(fileID host.FileID, } return ExecutableInfo{}, fmt.Errorf("failed to extract interval data: %w", err) } + if len(intervalData.Deltas) == 0 { + ef, errx := elfRef.GetELF() + if errx != nil { + return ExecutableInfo{}, errx + } + intervalData = synthesizeIntervalData(ef) + } // Also gather TSD info if applicable. if tpbase.IsPotentialTSDDSO(elfRef.FileName()) { @@ -232,33 +239,6 @@ func (mgr *ExecutableInfoManager) AddOrIncRef(fileID host.FileID, return info.ExecutableInfo, nil } -// AddSynthIntervalData should only be called once for a given file ID. It will error if it or -// AddOrIncRef has been previously called for the same file ID. Interpreter detection is skipped. -func (mgr *ExecutableInfoManager) AddSynthIntervalData( - fileID host.FileID, - data sdtypes.IntervalData, -) error { - state := mgr.state.WLock() - defer mgr.state.WUnlock(&state) - - if _, exists := state.executables[fileID]; exists { - return errors.New("AddSynthIntervalData: mapping already exists") - } - - ref, _, err := state.loadDeltas(fileID, data.Deltas) - if err != nil { - return fmt.Errorf("failed to load deltas: %w", err) - } - - state.executables[fileID] = &entry{ - ExecutableInfo: ExecutableInfo{Data: nil}, - mapRef: ref, - rc: 1, - } - - return nil -} - // RemoveOrDecRef decrements the reference counter of the executable being tracked. Once the RC // reaches zero, information about the file is removed from the manager and the corresponding // BPF maps. diff --git a/processmanager/synthdeltas.go b/processmanager/execinfomanager/synthdeltas.go similarity index 86% rename from processmanager/synthdeltas.go rename to processmanager/execinfomanager/synthdeltas.go index 2d05d7476..69263d94d 100644 --- a/processmanager/synthdeltas.go +++ b/processmanager/execinfomanager/synthdeltas.go @@ -1,9 +1,10 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" +package execinfomanager // import "go.opentelemetry.io/ebpf-profiler/processmanager/execinfomanager" import ( + "debug/elf" "sort" aa "golang.org/x/arch/arm64/arm64asm" @@ -21,9 +22,15 @@ const regFP = 29 // regLR is the arm64 link register (x30) number const regLR = 30 -// createVDSOSyntheticRecordNone returns no synthetic deltas when the kernel vDSO -// is known to have valid unwind information. -func createVDSOSyntheticRecordNone(_ *pfelf.File) sdtypes.IntervalData { +// synthesizeIntervalData creates synthetic stack deltas if possible. +// Currently supported for ARM64 vDSO only. +func synthesizeIntervalData(ef *pfelf.File) sdtypes.IntervalData { + if ef.Machine == elf.EM_AARCH64 { + soname, err := ef.DynString(elf.DT_SONAME) + if err == nil && soname[0] == "linux-vdso.so.1" { + return createVDSOSyntheticRecordArm64(ef) + } + } return sdtypes.IntervalData{} } diff --git a/processmanager/synthdeltas_test.go b/processmanager/execinfomanager/synthdeltas_test.go similarity index 92% rename from processmanager/synthdeltas_test.go rename to processmanager/execinfomanager/synthdeltas_test.go index 0fa5b00cc..4a7f090d1 100644 --- a/processmanager/synthdeltas_test.go +++ b/processmanager/execinfomanager/synthdeltas_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" +package execinfomanager // import "go.opentelemetry.io/ebpf-profiler/processmanager/execinfomanager" import ( "testing" diff --git a/processmanager/testdata/vdso.arch64.withframe b/processmanager/execinfomanager/testdata/vdso.arch64.withframe similarity index 100% rename from processmanager/testdata/vdso.arch64.withframe rename to processmanager/execinfomanager/testdata/vdso.arch64.withframe diff --git a/processmanager/manager.go b/processmanager/manager.go index 78865e071..8d21bc88f 100644 --- a/processmanager/manager.go +++ b/processmanager/manager.go @@ -22,7 +22,6 @@ import ( "go.opentelemetry.io/ebpf-profiler/lpm" "go.opentelemetry.io/ebpf-profiler/metrics" "go.opentelemetry.io/ebpf-profiler/nativeunwind" - sdtypes "go.opentelemetry.io/ebpf-profiler/nativeunwind/stackdeltatypes" "go.opentelemetry.io/ebpf-profiler/periodiccaller" pmebpf "go.opentelemetry.io/ebpf-profiler/processmanager/ebpf" eim "go.opentelemetry.io/ebpf-profiler/processmanager/execinfomanager" @@ -332,13 +331,3 @@ func (pm *ProcessManager) MaybeNotifyAPMAgent( return serviceName } - -// AddSynthIntervalData adds synthetic stack deltas to the manager. This is useful for cases where -// populating the information via the stack delta provider isn't viable, for example because the -// `.eh_frame` section for a binary is broken. If `AddSynthIntervalData` was called for a given -// file ID, the stack delta provider will not be consulted and the manually added stack deltas take -// precedence. -func (pm *ProcessManager) AddSynthIntervalData(fileID host.FileID, - data sdtypes.IntervalData) error { - return pm.eim.AddSynthIntervalData(fileID, data) -} diff --git a/processmanager/processinfo.go b/processmanager/processinfo.go index a446df5ae..38088a556 100644 --- a/processmanager/processinfo.go +++ b/processmanager/processinfo.go @@ -352,19 +352,7 @@ func (pm *ProcessManager) getELFInfo(pr process.Process, mapping *process.Mappin hostFileID := host.FileIDFromLibpf(fileID) info.fileID = hostFileID info.addressMapper = ef.GetAddressMapper() - if mapping.IsVDSO() { - intervals := createVDSOSyntheticRecord(ef) - if intervals.Deltas != nil { - if err := pm.AddSynthIntervalData(hostFileID, intervals); err != nil { - info.err = fmt.Errorf("failed to add synthetic deltas: %w", err) - } - } - } - // Do not cache the entry if synthetic stack delta loading failed, - // so next encounter of the VDSO will retry loading them. - if info.err == nil { - pm.elfInfoCache.Add(key, info) - } + pm.elfInfoCache.Add(key, info) pm.FileIDMapper.Set(hostFileID, fileID) if pm.reporter.ExecutableKnown(fileID) { diff --git a/processmanager/synthdeltas_arm64.go b/processmanager/synthdeltas_arm64.go deleted file mode 100644 index bb0b7dcd0..000000000 --- a/processmanager/synthdeltas_arm64.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build arm64 - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" - -var createVDSOSyntheticRecord = createVDSOSyntheticRecordArm64 diff --git a/processmanager/synthdeltas_other.go b/processmanager/synthdeltas_other.go deleted file mode 100644 index 68a709072..000000000 --- a/processmanager/synthdeltas_other.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !arm64 - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" - -var createVDSOSyntheticRecord = createVDSOSyntheticRecordNone