Skip to content

Commit

Permalink
info: Add metadata to instructions returned by program info
Browse files Browse the repository at this point in the history
The instructions returned by program info gotten from the kernel did
not contain any metadata such as line info or function info. This
makes it harder to read the instructions when comparing the xlated
instruction in the kernel with the spec.

This commit uses the line info and function info that is available via
the program info and adds it to the returned instructions.

Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
  • Loading branch information
dylandreimerink committed Aug 16, 2023
1 parent ebd22d5 commit 917fec1
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
57 changes: 54 additions & 3 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ type ProgramInfo struct {

maps []MapID
insns []byte

lineInfo []byte
funcInfo []byte
}

func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
Expand Down Expand Up @@ -128,10 +131,13 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
// Start with a clean struct for the second call, otherwise we may get EFAULT.
var info2 sys.ProgInfo

makeSecondCall := false

if info.NrMapIds > 0 {
pi.maps = make([]MapID, info.NrMapIds)
info2.NrMapIds = info.NrMapIds
info2.MapIds = sys.NewPointer(unsafe.Pointer(&pi.maps[0]))
makeSecondCall = true
} else if haveProgramInfoMapIDs() == nil {
// This program really has no associated maps.
pi.maps = make([]MapID, 0)
Expand All @@ -150,9 +156,26 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
pi.insns = make([]byte, info.XlatedProgLen)
info2.XlatedProgLen = info.XlatedProgLen
info2.XlatedProgInsns = sys.NewSlicePointer(pi.insns)
makeSecondCall = true
}

if info.NrLineInfo > 0 {
pi.lineInfo = make([]byte, btf.LineInfoSize*info.NrLineInfo)
info2.LineInfo = sys.NewSlicePointer(pi.lineInfo)
info2.LineInfoRecSize = btf.LineInfoSize
info2.NrLineInfo = info.NrLineInfo
makeSecondCall = true
}

if info.NrMapIds > 0 || info.XlatedProgLen > 0 {
if info.NrFuncInfo > 0 {
pi.funcInfo = make([]byte, btf.FuncInfoSize*info.NrFuncInfo)
info2.FuncInfo = sys.NewSlicePointer(pi.funcInfo)
info2.FuncInfoRecSize = btf.FuncInfoSize
info2.NrFuncInfo = info.NrFuncInfo
makeSecondCall = true
}

if makeSecondCall {
if err := sys.ObjInfo(fd, &info2); err != nil {
return nil, err
}
Expand Down Expand Up @@ -259,8 +282,36 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
return nil, fmt.Errorf("unmarshaling instructions: %w", err)
}

// Tag the first instruction with the name of the program, if available.
insns[0] = insns[0].WithSymbol(pi.Name)
if pi.btf != 0 {
btfh, err := btf.NewHandleFromID(pi.btf)
if err != nil {
return nil, fmt.Errorf("unable to get BTF handle: %w", err)
}
defer btfh.Close()

spec, err := btfh.Spec(nil)
if err != nil {
return nil, fmt.Errorf("unable to get BTF spec: %w", err)
}

b := btf.NewExtInfosBuilder(spec)
err = b.AddLineInfos(pi.Name, pi.lineInfo)
if err != nil {
return nil, fmt.Errorf("unable to add line infos: %w", err)
}
err = b.AddFuncInfos(pi.Name, pi.funcInfo)
if err != nil {
return nil, fmt.Errorf("unable to add func infos: %w", err)
}
b.Build().Assign(insns, pi.Name)
}

fn := btf.FuncMetadata(&insns[0])
if fn != nil {
insns[0] = insns[0].WithSymbol(fn.Name)
} else {
insns[0] = insns[0].WithSymbol(pi.Name)
}

return insns, nil
}
Expand Down
40 changes: 40 additions & 0 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/btf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/testutils"
Expand Down Expand Up @@ -365,3 +366,42 @@ func testStats(prog *Program) error {
func TestHaveProgramInfoMapIDs(t *testing.T) {
testutils.CheckFeatureTest(t, haveProgramInfoMapIDs)
}

func TestProgInfoExtBTF(t *testing.T) {
testutils.SkipOnOldKernel(t, "5.0", "Program BTF (func/line_info)")

spec, err := LoadCollectionSpec("testdata/raw_tracepoint-el.elf")
if err != nil {
panic(err)
}

coll, err := NewCollection(spec)
if err != nil {
panic(err)
}
defer coll.Close()

info, err := coll.Programs["sched_process_exec"].Info()
if err != nil {
panic(err)
}

inst, err := info.Instructions()
if err != nil {
panic(err)
}

const expectedSource = "\treturn 0;"
if inst[0].Source().String() != expectedSource {
t.Fatalf("Source of first instruction incorrect. Got '%s', expected: '%s'", inst[0].Source().String(), expectedSource)
}

fn := btf.FuncMetadata(&inst[0])
if fn == nil {
t.Fatal("Func metadata missing")
}

if fn.Name != "sched_process_exec" {
t.Fatalf("Func metadata incorrect. Got '%s', expected: 'sched_process_exec'", fn.Name)
}
}

0 comments on commit 917fec1

Please sign in to comment.