Skip to content

Commit 80bccc0

Browse files
committed
Override oomprof elf reader to delegate to pfelf
1 parent 28a0412 commit 80bccc0

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package oomwatcher // import "go.opentelemetry.io/ebpf-profiler/interpreter/oomwatcher"
5+
6+
import (
7+
"errors"
8+
"fmt"
9+
10+
"github.com/parca-dev/oomprof/oomprof"
11+
"go.opentelemetry.io/ebpf-profiler/libpf"
12+
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
13+
)
14+
15+
// pfelfReader implements oomprof.ELFReader using libpf/pfelf.
16+
type pfelfReader struct{}
17+
18+
// Open opens an ELF file using pfelf.
19+
func (r *pfelfReader) Open(path string) (oomprof.ELFFile, error) {
20+
file, err := pfelf.Open(path)
21+
if err != nil {
22+
return nil, err
23+
}
24+
return &pfelfFile{file: file}, nil
25+
}
26+
27+
// pfelfFile implements oomprof.ELFFile using libpf/pfelf.File.
28+
type pfelfFile struct {
29+
file *pfelf.File
30+
}
31+
32+
// Close closes the ELF file.
33+
func (f *pfelfFile) Close() error {
34+
return f.file.Close()
35+
}
36+
37+
// GetBuildID returns the build ID of the ELF file.
38+
func (f *pfelfFile) GetBuildID() (string, error) {
39+
return f.file.GetBuildID()
40+
}
41+
42+
// GoVersion returns the Go version the binary was built with.
43+
func (f *pfelfFile) GoVersion() (string, error) {
44+
return f.file.GoVersion()
45+
}
46+
47+
// LookupSymbol looks up a symbol by name and returns its address.
48+
func (f *pfelfFile) LookupSymbol(name string) (oomprof.SymbolInfo, error) {
49+
sym, err := f.file.LookupSymbol(libpf.SymbolName(name))
50+
if err != nil {
51+
if errors.Is(err, libpf.ErrSymbolNotFound) {
52+
return oomprof.SymbolInfo{}, fmt.Errorf("symbol %s not found", name)
53+
}
54+
return oomprof.SymbolInfo{}, err
55+
}
56+
57+
return oomprof.SymbolInfo{
58+
Name: string(sym.Name),
59+
Address: uint64(sym.Address),
60+
}, nil
61+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package oomwatcher
5+
6+
import (
7+
"testing"
8+
9+
"github.com/parca-dev/oomprof/oomprof"
10+
)
11+
12+
func TestPfelfReaderImplementsInterface(t *testing.T) {
13+
// Verify that pfelfReader implements oomprof.ELFReader
14+
var _ oomprof.ELFReader = &pfelfReader{}
15+
}
16+
17+
func TestPfelfFileImplementsInterface(t *testing.T) {
18+
// Verify that pfelfFile implements oomprof.ELFFile
19+
var _ oomprof.ELFFile = &pfelfFile{}
20+
}
21+
22+
func TestInit(t *testing.T) {
23+
// Verify that the global ELF reader is set
24+
reader := oomprof.GetELFReader()
25+
if reader == nil {
26+
t.Fatal("Expected global ELF reader to be set")
27+
}
28+
29+
// Verify it's our implementation by checking the type
30+
if _, ok := reader.(*pfelfReader); !ok {
31+
t.Errorf("Expected global ELF reader to be *pfelfReader, got %T", reader)
32+
}
33+
}
34+
35+
func TestPfelfReaderOpenAndRead(t *testing.T) {
36+
reader := &pfelfReader{}
37+
38+
// Try to open the Go binary itself (should be a Go binary)
39+
file, err := reader.Open("/home/tpr/.gvm/gos/go1.25.1/bin/go")
40+
if err != nil {
41+
t.Skipf("Could not open Go binary for testing: %v", err)
42+
}
43+
defer file.Close()
44+
45+
// Test GetBuildID
46+
buildID, err := file.GetBuildID()
47+
if err != nil {
48+
t.Logf("GetBuildID returned error (may be expected): %v", err)
49+
} else {
50+
t.Logf("Build ID: %s", buildID)
51+
if buildID == "" {
52+
t.Error("Expected non-empty build ID")
53+
}
54+
}
55+
56+
// Test GoVersion
57+
goVersion, err := file.GoVersion()
58+
if err != nil {
59+
t.Fatalf("GoVersion failed: %v", err)
60+
}
61+
if goVersion == "" {
62+
t.Error("Expected non-empty Go version")
63+
}
64+
t.Logf("Go version: %s", goVersion)
65+
66+
// Test LookupSymbol - try to find a common Go symbol
67+
symInfo, err := file.LookupSymbol("runtime.main")
68+
if err != nil {
69+
t.Logf("Could not find runtime.main symbol: %v", err)
70+
} else {
71+
t.Logf("Found symbol runtime.main at address 0x%x", symInfo.Address)
72+
if symInfo.Name != "runtime.main" {
73+
t.Errorf("Expected symbol name 'runtime.main', got '%s'", symInfo.Name)
74+
}
75+
if symInfo.Address == 0 {
76+
t.Error("Expected non-zero address for runtime.main")
77+
}
78+
}
79+
}

interpreter/oomwatcher/oomwatcher.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import (
1414
"go.opentelemetry.io/ebpf-profiler/remotememory"
1515
)
1616

17+
func init() {
18+
// Set the pfelf-based ELF reader as the default for oomprof.
19+
// This provides optimized ELF file reading compared to debug/elf.
20+
oomprof.SetELFReader(&pfelfReader{})
21+
}
22+
1723
// oomWatcherData holds per-executable data for the OOM watcher observer.
1824
type oomWatcherData struct {
1925
state *oomprof.State

0 commit comments

Comments
 (0)