Skip to content

Commit 3eaf7ba

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

File tree

18 files changed

+596
-771
lines changed

18 files changed

+596
-771
lines changed

interpreter/go/go.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (g *goInstance) Symbolize(frame *host.Frame, frames *libpf.Frames) error {
9999
sfCounter := successfailurecounter.New(&g.successCount, &g.failCount)
100100
defer sfCounter.DefaultToFailure()
101101

102-
sourceFile, lineNo, fn := g.d.pclntab.Symbolize(uintptr(frame.Lineno))
102+
sourceFile, lineNo, fn := g.d.pclntab.Symbolize(uint64(frame.Lineno))
103103
if fn == "" {
104104
return fmt.Errorf("failed to symbolize 0x%x", frame.Lineno)
105105
}
@@ -115,7 +115,3 @@ func (g *goInstance) Symbolize(frame *host.Frame, frames *libpf.Frames) error {
115115
sfCounter.ReportSuccess()
116116
return nil
117117
}
118-
119-
func (g *goInstance) ReleaseResources() error {
120-
return g.d.pclntab.SetDontNeed()
121-
}

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/hotspot/data.go

Lines changed: 8 additions & 19 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"
@@ -399,45 +398,35 @@ func locateJvmciVMStructs(ef *pfelf.File) (libpf.Address, error) {
399398
const maxDataReadSize = 1 * 1024 * 1024 // seen in practice: 192 KiB
400399
const maxRodataReadSize = 4 * 1024 * 1024 // seen in practice: 753 KiB
401400

402-
rodataSec := ef.Section(".rodata")
403-
if rodataSec == nil {
401+
rodata := ef.Section(".rodata")
402+
if rodata == nil {
404403
return 0, errors.New("unable to find `.rodata` section")
405404
}
406405

407-
rodata, err := rodataSec.Data(maxRodataReadSize)
406+
offs, err := libpf.SearchReader(rodata, []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
}
425419

426-
data, err := dataSec.Data(maxDataReadSize)
420+
offs, err = libpf.SearchReader(data, ptrEncoded)
427421
if err != nil {
428-
return 0, err
429-
}
430-
431-
offs = bytes.Index(data, ptrEncoded)
432-
if offs == -1 {
433422
return 0, errors.New("unable to find string pointer")
434423
}
435424

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

443432
// 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: 6 additions & 12 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"
@@ -19,7 +18,6 @@ import (
1918
"go.opentelemetry.io/ebpf-profiler/interpreter"
2019
"go.opentelemetry.io/ebpf-profiler/libpf"
2120
"go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
22-
"go.opentelemetry.io/ebpf-profiler/libpf/pfunsafe"
2321
"go.opentelemetry.io/ebpf-profiler/remotememory"
2422
"go.opentelemetry.io/ebpf-profiler/support"
2523
)
@@ -166,22 +164,18 @@ func determinePHPVersion(ef *pfelf.File) (uint, error) {
166164
}
167165

168166
needle := []byte("X-Powered-By: PHP/")
169-
for _, segment := range ef.ROData {
170-
rodata, err := segment.Data(maxPHPRODataSize)
167+
for _, ph := range ef.ROData {
168+
offs, err := libpf.SearchReader(ph, needle)
171169
if err != nil {
172-
return 0, err
173-
}
174-
idx := bytes.Index(rodata, needle)
175-
if idx < 0 {
176170
continue
177171
}
178172

179-
idx += len(needle)
180-
zeroIdx := bytes.IndexByte(rodata[idx:], 0)
181-
if zeroIdx < 0 {
173+
verStr, err := libpf.ReadString(ph, offs + int64(len(needle)))
174+
if err != nil {
182175
continue
183176
}
184-
version, err := versionExtract(pfunsafe.ToString(rodata[idx : idx+zeroIdx]))
177+
178+
version, err := versionExtract(verStr)
185179
if err != nil {
186180
continue
187181
}

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
}

libpf/io.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf"
5+
6+
import (
7+
"bytes"
8+
"errors"
9+
"io"
10+
)
11+
12+
var errStringTooLong = errors.New("too long string")
13+
14+
func ReadString(r io.ReaderAt, offset int64) (string, error) {
15+
var data [4096]byte
16+
17+
// Read in chunks of 128 bytes
18+
const chunkSize = 128
19+
for i := 0; i < len(data) - chunkSize; i += chunkSize {
20+
n, err := r.ReadAt(data[i:i+chunkSize], int64(i) + offset)
21+
zeroIdx := bytes.IndexByte(data[i:i+n], 0)
22+
if zeroIdx >= 0 {
23+
return string(data[:i+zeroIdx]), nil
24+
}
25+
if err != nil {
26+
return "", errStringTooLong
27+
}
28+
}
29+
return "", io.EOF
30+
}
31+
32+
func SearchReader(r io.ReaderAt, needle []byte) (int64, error) {
33+
var buf[64*1024]byte
34+
35+
fileOffs := int64(0)
36+
for {
37+
n, err := r.ReadAt(buf[:], fileOffs)
38+
// process 'n' bytes
39+
bufOffs := bytes.Index(buf[:n], needle)
40+
if bufOffs >= 0 {
41+
return fileOffs + int64(bufOffs), nil
42+
}
43+
if n < len(needle) || err != nil {
44+
return -1, err
45+
}
46+
fileOffs += int64(n - len(needle) + 1)
47+
}
48+
return -1, io.EOF
49+
}

0 commit comments

Comments
 (0)