Skip to content

Commit 41862a3

Browse files
committed
pfelf, interpreters, elfunwindinfo: refactor to not use mmap
instead read the section and program header data using io.ReaderAt
1 parent b8c1919 commit 41862a3

20 files changed

Lines changed: 999 additions & 817 deletions

File tree

interpreter/go/go.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,19 @@ func (g *goInstance) Symbolize(frame *host.Frame, frames *libpf.Frames) error {
109109
sfCounter := successfailurecounter.New(&g.successCount, &g.failCount)
110110
defer sfCounter.DefaultToFailure()
111111

112-
sourceFile, lineNo, fn := g.d.pclntab.Symbolize(uintptr(frame.Lineno))
113-
if fn == "" {
112+
sourceFile, lineNo, fn := g.d.pclntab.Symbolize(uint64(frame.Lineno))
113+
if fn == libpf.NullString {
114114
return fmt.Errorf("failed to symbolize 0x%x", frame.Lineno)
115115
}
116116

117117
frames.Append(&libpf.Frame{
118118
Type: libpf.GoFrame,
119119
//TODO: File: convert the frame.File (host.FileID) to libpf.FileID here
120120
AddressOrLineno: frame.Lineno,
121-
FunctionName: libpf.Intern(fn),
122-
SourceFile: libpf.Intern(sourceFile),
121+
FunctionName: fn,
122+
SourceFile: sourceFile,
123123
SourceLine: libpf.SourceLineno(lineNo),
124124
})
125125
sfCounter.ReportSuccess()
126126
return nil
127127
}
128-
129-
func (g *goInstance) ReleaseResources() error {
130-
return g.d.pclntab.SetDontNeed()
131-
}

interpreter/golabels/tls_amd64.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ func extractTLSGOffset(f *pfelf.File) (int32, error) {
4040
}
4141

4242
sz := int(min(sym.Size, 128))
43-
code, err := f.VirtualMemory(int64(sym.Address), sz, sz)
44-
if err != nil {
43+
code := make([]byte, sz)
44+
if _, err = f.ReadAt(code, int64(sym.Address)); err != nil {
4545
return 0, err
4646
}
4747

interpreter/golabels/tls_arm64.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ func extractTLSGOffset(f *pfelf.File) (int32, error) {
6060
return 0, err
6161
}
6262
}
63-
b, err := f.VirtualMemory(int64(sym.Address), 32, 32)
64-
if err != nil {
63+
sz := int(min(sym.Size, 32))
64+
b := make([]byte, sz)
65+
if _, err := f.ReadAt(b, int64(sym.Address)); err != nil {
6566
return 0, err
6667
}
6768
for ; len(b) > 0; b = b[4:] {

interpreter/hotspot/data.go

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package hotspot // import "go.opentelemetry.io/ebpf-profiler/interpreter/hotspot"
55

66
import (
7-
"bytes"
87
"encoding/binary"
98
"errors"
109
"fmt"
@@ -18,6 +17,7 @@ import (
1817

1918
"go.opentelemetry.io/ebpf-profiler/interpreter"
2019
"go.opentelemetry.io/ebpf-profiler/libpf"
20+
"go.opentelemetry.io/ebpf-profiler/libpf/pfatbuf"
2121
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
2222
"go.opentelemetry.io/ebpf-profiler/libpf/xsync"
2323
"go.opentelemetry.io/ebpf-profiler/lpm"
@@ -396,48 +396,38 @@ func (d *hotspotData) Unload(_ interpreter.EbpfHandler) {
396396
//
397397
//nolint:lll
398398
func locateJvmciVMStructs(ef *pfelf.File) (libpf.Address, error) {
399-
const maxDataReadSize = 1 * 1024 * 1024 // seen in practice: 192 KiB
400-
const maxRodataReadSize = 4 * 1024 * 1024 // seen in practice: 753 KiB
401-
402-
rodataSec := ef.Section(".rodata")
403-
if rodataSec == nil {
399+
rodata := ef.Section(".rodata")
400+
if rodata == nil {
404401
return 0, errors.New("unable to find `.rodata` section")
405402
}
403+
cache := pfatbuf.Cache{}
404+
cache.Init(rodata)
406405

407-
rodata, err := rodataSec.Data(maxRodataReadSize)
406+
offs, err := cache.Search([]byte("Klass_vtable_start_offset"))
408407
if err != nil {
409-
return 0, err
410-
}
411-
412-
offs := bytes.Index(rodata, []byte("Klass_vtable_start_offset"))
413-
if offs == -1 {
414408
return 0, errors.New("unable to find string for heuristic")
415409
}
416410

417-
ptr := rodataSec.Addr + uint64(offs)
411+
ptr := rodata.Addr + uint64(offs)
418412
ptrEncoded := make([]byte, 8)
419413
binary.LittleEndian.PutUint64(ptrEncoded, ptr)
420414

421-
dataSec := ef.Section(".data")
422-
if dataSec == nil {
415+
data := ef.Section(".data")
416+
if data == nil {
423417
return 0, errors.New("unable to find `.data` section")
424418
}
419+
cache.Init(data)
425420

426-
data, err := dataSec.Data(maxDataReadSize)
421+
offs, err = cache.Search(ptrEncoded)
427422
if err != nil {
428-
return 0, err
429-
}
430-
431-
offs = bytes.Index(data, ptrEncoded)
432-
if offs == -1 {
433423
return 0, errors.New("unable to find string pointer")
434424
}
435425

436426
// 8 in the expression below is what we'd usually read from
437427
// gHotSpotVMStructEntryFieldNameOffset. This value unfortunately lives in
438428
// BSS, so we have no choice but to hard-code it. Fortunately enough this
439429
// offset hasn't changed since at least JDK 9.
440-
return libpf.Address(dataSec.Addr + uint64(offs) - 8), nil
430+
return libpf.Address(data.Addr + uint64(offs) - 8), nil
441431
}
442432

443433
// forEachItem walks the given struct reflection fields recursively, and calls the visitor

interpreter/instancestubs.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,3 @@ func (is *InstanceStubs) Symbolize(*host.Frame, *libpf.Frames) error {
3333
func (is *InstanceStubs) GetAndResetMetrics() ([]metrics.Metric, error) {
3434
return []metrics.Metric{}, nil
3535
}
36-
37-
func (is *InstanceStubs) ReleaseResources() error {
38-
return nil
39-
}

interpreter/multi.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,3 @@ func (m *MultiInstance) GetAndResetMetrics() ([]metrics.Metric, error) {
141141

142142
return allMetrics, errors.Join(errs...)
143143
}
144-
145-
func (m *MultiInstance) ReleaseResources() error {
146-
var errs []error
147-
for _, instance := range m.instances {
148-
err := instance.ReleaseResources()
149-
if err != nil {
150-
errs = append(errs, err)
151-
}
152-
}
153-
return errors.Join(errs...)
154-
}

interpreter/php/php.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package php // import "go.opentelemetry.io/ebpf-profiler/interpreter/php"
55

66
import (
7-
"bytes"
87
"debug/elf"
98
"errors"
109
"fmt"
@@ -18,8 +17,8 @@ import (
1817

1918
"go.opentelemetry.io/ebpf-profiler/interpreter"
2019
"go.opentelemetry.io/ebpf-profiler/libpf"
20+
"go.opentelemetry.io/ebpf-profiler/libpf/pfatbuf"
2121
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
22-
"go.opentelemetry.io/ebpf-profiler/libpf/pfunsafe"
2322
"go.opentelemetry.io/ebpf-profiler/remotememory"
2423
"go.opentelemetry.io/ebpf-profiler/support"
2524
)
@@ -30,12 +29,6 @@ const (
3029
ZEND_VM_KIND_HYBRID = (1 << 2)
3130
)
3231

33-
const (
34-
// maxPHPRODataSize is the maximum PHP RO Data segment size to scan
35-
// (currently the largest seen is about 9M)
36-
maxPHPRODataSize = 16 * 1024 * 1024
37-
)
38-
3932
var (
4033
// evalCodeFunctionName is a placeholder name to show that code has been evaluated
4134
// using eval in PHP.
@@ -165,23 +158,21 @@ func determinePHPVersion(ef *pfelf.File) (uint, error) {
165158
return 0, errors.New("no RO data")
166159
}
167160

161+
cache := pfatbuf.Cache{}
168162
needle := []byte("X-Powered-By: PHP/")
169-
for _, segment := range ef.ROData {
170-
rodata, err := segment.Data(maxPHPRODataSize)
163+
for _, ph := range ef.ROData {
164+
cache.Init(ph)
165+
166+
offs, err := cache.Search(needle)
171167
if err != nil {
172-
return 0, err
173-
}
174-
idx := bytes.Index(rodata, needle)
175-
if idx < 0 {
176168
continue
177169
}
178170

179-
idx += len(needle)
180-
zeroIdx := bytes.IndexByte(rodata[idx:], 0)
181-
if zeroIdx < 0 {
171+
verStr, err := cache.UnsafeStringAt(offs + int64(len(needle)))
172+
if err != nil {
182173
continue
183174
}
184-
version, err := versionExtract(pfunsafe.ToString(rodata[idx : idx+zeroIdx]))
175+
version, err := versionExtract(verStr)
185176
if err != nil {
186177
continue
187178
}

interpreter/types.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,4 @@ type Instance interface {
154154
// GetAndResetMetrics collects the metrics from the Instance and resets
155155
// the counters to their initial value.
156156
GetAndResetMetrics() ([]metrics.Metric, error)
157-
158-
// Release resources that are used to symbolize a stack.
159-
ReleaseResources() error
160157
}

0 commit comments

Comments
 (0)