Skip to content

Commit

Permalink
fixup! btf,info: Fix bad instruction offset when parsing infos from k…
Browse files Browse the repository at this point in the history
…ernel

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
  • Loading branch information
lmb committed Oct 19, 2023
1 parent b906189 commit 293574a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 102 deletions.
60 changes: 10 additions & 50 deletions btf/ext_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,14 +333,6 @@ func parseExtInfoRecordSize(r io.Reader, bo binary.ByteOrder) (uint32, error) {
return recordSize, nil
}

// parseDir indicates from which source the BTF is parsed.
type parseDir int

const (
parseFromELF parseDir = iota
parseFromKernel
)

// FuncInfos contains a sorted list of func infos.
type FuncInfos struct {
infos []funcInfo
Expand Down Expand Up @@ -399,30 +391,14 @@ func newFuncInfos(bfis []bpfFuncInfo, spec *Spec) (FuncInfos, error) {
return fis, nil
}

// LoadFuncInfos parses btf ELF func info in wire format.
// LoadFuncInfos parses BTF func info in kernel wire format.
func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (FuncInfos, error) {
fis, err := parseFuncInfoRecords(
reader,
bo,
FuncInfoSize,
recordNum,
parseFromELF,
)
if err != nil {
return FuncInfos{}, fmt.Errorf("parsing BTF func info: %w", err)
}

return newFuncInfos(fis, spec)
}

// LoadFuncInfos parses btf kernel func info in wire format.
func LoadKernelFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (FuncInfos, error) {
fis, err := parseFuncInfoRecords(
reader,
bo,
FuncInfoSize,
recordNum,
parseFromKernel,
false,
)
if err != nil {
return FuncInfos{}, fmt.Errorf("parsing BTF func info: %w", err)
Expand Down Expand Up @@ -466,7 +442,7 @@ func parseFuncInfos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
return nil, err
}

records, err := parseFuncInfoRecords(r, bo, recordSize, infoHeader.NumInfo, parseFromELF)
records, err := parseFuncInfoRecords(r, bo, recordSize, infoHeader.NumInfo, true)
if err != nil {
return nil, fmt.Errorf("section %v: %w", secName, err)
}
Expand All @@ -478,7 +454,7 @@ func parseFuncInfos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
// parseFuncInfoRecords parses a stream of func_infos into a funcInfos.
// These records appear after a btf_ext_info_sec header in the func_info
// sub-section of .BTF.ext.
func parseFuncInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, recordNum uint32, dir parseDir) ([]bpfFuncInfo, error) {
func parseFuncInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, recordNum uint32, offsetInBytes bool) ([]bpfFuncInfo, error) {
var out []bpfFuncInfo
var fi bpfFuncInfo

Expand All @@ -492,7 +468,7 @@ func parseFuncInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, r
return nil, fmt.Errorf("can't read function info: %v", err)
}

if dir == parseFromELF {
if offsetInBytes {
if fi.InsnOff%asm.InstructionSize != 0 {
return nil, fmt.Errorf("offset %v is not aligned with instruction size", fi.InsnOff)
}
Expand Down Expand Up @@ -564,30 +540,14 @@ type bpfLineInfo struct {
LineCol uint32
}

// LoadLineInfos parses btf ELF line info in wire format.
// LoadLineInfos parses BTF line info in kernel wire format.
func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (LineInfos, error) {
lis, err := parseLineInfoRecords(
reader,
bo,
LineInfoSize,
recordNum,
parseFromELF,
)
if err != nil {
return LineInfos{}, fmt.Errorf("parsing BTF line info: %w", err)
}

return newLineInfos(lis, spec.strings)
}

// LoadKernelLineInfos parses btf kernel line info in wire format.
func LoadKernelLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (LineInfos, error) {
lis, err := parseLineInfoRecords(
reader,
bo,
LineInfoSize,
recordNum,
parseFromKernel,
false,
)
if err != nil {
return LineInfos{}, fmt.Errorf("parsing BTF line info: %w", err)
Expand Down Expand Up @@ -693,7 +653,7 @@ func parseLineInfos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
return nil, err
}

records, err := parseLineInfoRecords(r, bo, recordSize, infoHeader.NumInfo, parseFromELF)
records, err := parseLineInfoRecords(r, bo, recordSize, infoHeader.NumInfo, true)
if err != nil {
return nil, fmt.Errorf("section %v: %w", secName, err)
}
Expand All @@ -705,7 +665,7 @@ func parseLineInfos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
// parseLineInfoRecords parses a stream of line_infos into a lineInfos.
// 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, dir parseDir) ([]bpfLineInfo, error) {
func parseLineInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, recordNum uint32, offsetInBytes bool) ([]bpfLineInfo, error) {
var out []bpfLineInfo
var li bpfLineInfo

Expand All @@ -719,7 +679,7 @@ func parseLineInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, r
return nil, fmt.Errorf("can't read line info: %v", err)
}

if dir == parseFromELF {
if offsetInBytes {
if li.InsnOff%asm.InstructionSize != 0 {
return nil, fmt.Errorf("offset %v is not aligned with instruction size", li.InsnOff)
}
Expand Down
4 changes: 2 additions & 2 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
return nil, fmt.Errorf("unable to get BTF spec: %w", err)
}

lineInfos, err := btf.LoadKernelLineInfos(
lineInfos, err := btf.LoadLineInfos(
bytes.NewReader(pi.lineInfos),
internal.NativeEndian,
pi.numLineInfos,
Expand All @@ -321,7 +321,7 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
return nil, fmt.Errorf("parse line info: %w", err)
}

funcInfos, err := btf.LoadKernelFuncInfos(
funcInfos, err := btf.LoadFuncInfos(
bytes.NewReader(pi.funcInfos),
internal.NativeEndian,
pi.numFuncInfos,
Expand Down
94 changes: 44 additions & 50 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,66 +370,60 @@ func TestHaveProgramInfoMapIDs(t *testing.T) {
func TestProgInfoExtBTF(t *testing.T) {
testutils.SkipOnOldKernel(t, "5.0", "Program BTF (func/line_info)")

testutils.Files(t, testutils.Glob(t, "testdata/loader-??.elf"), func(t *testing.T, file string) {
spec, err := LoadCollectionSpec(file)
if err != nil {
t.Fatal(err)
}

if spec.ByteOrder != internal.NativeEndian {
return
}

var obj struct {
Main *Program `ebpf:"xdp_prog"`
}
spec, err := LoadCollectionSpec(fmt.Sprintf("testdata/loader-%s.elf", internal.ClangEndian))
if err != nil {
t.Fatal(err)
}

err = spec.LoadAndAssign(&obj, nil)
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
}
defer obj.Main.Close()
var obj struct {
Main *Program `ebpf:"xdp_prog"`
}

info, err := obj.Main.Info()
if err != nil {
t.Fatal(err)
}
err = spec.LoadAndAssign(&obj, nil)
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
}
defer obj.Main.Close()

inst, err := info.Instructions()
if err != nil {
t.Fatal(err)
}
info, err := obj.Main.Info()
if err != nil {
t.Fatal(err)
}

expectedLineInfoCount := 26
expectedFuncInfo := map[string]bool{
"xdp_prog": false,
"static_fn": false,
"global_fn2": false,
"global_fn3": false,
}
inst, err := info.Instructions()
if err != nil {
t.Fatal(err)
}

lineInfoCount := 0
expectedLineInfoCount := 26
expectedFuncInfo := map[string]bool{
"xdp_prog": false,
"static_fn": false,
"global_fn2": false,
"global_fn3": false,
}

for _, ins := range inst {
if ins.Source() != nil {
lineInfoCount++
}
lineInfoCount := 0

fn := btf.FuncMetadata(&ins)
if fn != nil {
expectedFuncInfo[fn.Name] = true
}
for _, ins := range inst {
if ins.Source() != nil {
lineInfoCount++
}

if lineInfoCount != expectedLineInfoCount {
t.Errorf("expected %d line info entries, got %d", expectedLineInfoCount, lineInfoCount)
fn := btf.FuncMetadata(&ins)
if fn != nil {
expectedFuncInfo[fn.Name] = true
}
}

for fn, found := range expectedFuncInfo {
if !found {
t.Errorf("func %q not found", fn)
}
if lineInfoCount != expectedLineInfoCount {
t.Errorf("expected %d line info entries, got %d", expectedLineInfoCount, lineInfoCount)
}

for fn, found := range expectedFuncInfo {
if !found {
t.Errorf("func %q not found", fn)
}
})
}
}

0 comments on commit 293574a

Please sign in to comment.