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
19 changes: 8 additions & 11 deletions btf/ext_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,20 +666,19 @@ func parseLineInfos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
// These records appear after a btf_ext_info_sec header in the line_info
// sub-section of .BTF.ext.
func parseLineInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, recordNum uint32, offsetInBytes bool) ([]bpfLineInfo, error) {
var li bpfLineInfo

if exp, got := uint32(binary.Size(li)), recordSize; exp != got {
if exp, got := uint32(binary.Size(bpfLineInfo{})), recordSize; exp != got {
// BTF blob's record size is longer than we know how to parse.
return nil, fmt.Errorf("expected LineInfo record size %d, but BTF blob contains %d", exp, got)
}

out := make([]bpfLineInfo, 0, recordNum)
for i := uint32(0); i < recordNum; i++ {
if err := binary.Read(r, bo, &li); err != nil {
return nil, fmt.Errorf("can't read line info: %v", err)
}
out := make([]bpfLineInfo, recordNum)
if err := binary.Read(r, bo, out); err != nil {
return nil, fmt.Errorf("can't read line info: %v", err)
}

if offsetInBytes {
if offsetInBytes {
for i := range out {
li := &out[i]
if li.InsnOff%asm.InstructionSize != 0 {
return nil, fmt.Errorf("offset %v is not aligned with instruction size", li.InsnOff)
}
Expand All @@ -688,8 +687,6 @@ func parseLineInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, r
// Convert as early as possible.
li.InsnOff /= asm.InstructionSize
}

out = append(out, li)
}

return out, nil
Expand Down
31 changes: 31 additions & 0 deletions btf/ext_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package btf

import (
"bytes"
"encoding/binary"
"strings"
"testing"

"github.com/cilium/ebpf/internal"

"github.com/go-quicktest/qt"
)

func TestParseExtInfoBigRecordSize(t *testing.T) {
Expand All @@ -23,3 +26,31 @@ func TestParseExtInfoBigRecordSize(t *testing.T) {
t.Error("Parsing line info with large record size doesn't return an error")
}
}

func BenchmarkParseLineInfoRecords(b *testing.B) {
size := uint32(binary.Size(bpfLineInfo{}))
count := uint32(4096)
buf := make([]byte, size*count)

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
parseLineInfoRecords(bytes.NewReader(buf), internal.NativeEndian, size, count, true)
}
}

func TestParseLineInfoRecordsAllocations(t *testing.T) {
size := uint32(binary.Size(bpfLineInfo{}))
count := uint32(4096)
buf := make([]byte, size*count)

allocs := testing.AllocsPerRun(5, func() {
parseLineInfoRecords(bytes.NewReader(buf), internal.NativeEndian, size, count, true)
})

// 7 is the number of allocations on go 1.22
// what we want to test is that we are not allocating
// once per record
qt.Assert(t, qt.IsTrue(allocs <= 7))
}