Skip to content

Commit

Permalink
link: Add Info interface support for perf link
Browse files Browse the repository at this point in the history
Implementing Info function (Link interface) for perf event
link, it's now possibe to retrieve link's data with:

  info, err := link.Info()

to access kprobe info data:

  pevent := info.PerfEvent()
  switch pevent.Type {
  case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE:
    kprobe := pevent.Kprobe()

to access uprobe info data:

  case sys.BPF_PERF_EVENT_UPROBE, sys.BPF_PERF_EVENT_URETPROBE:
    uprobe := pevent.Uprobe()

to access tracepoint info data:

  case sys.BPF_PERF_EVENT_TRACEPOINT:
    tp := pevent.Tracepoint()

to access perf event info data:

  case sys.BPF_PERF_EVENT_EVENT:
    event := pevent.Event()

Signed-off-by: Jiri Olsa <[email protected]>
  • Loading branch information
olsajiri committed Feb 2, 2024
1 parent b017d04 commit ecb4d92
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
24 changes: 24 additions & 0 deletions link/link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,30 @@ func testLink(t *testing.T, link Link, prog *ebpf.Program) {
t.Fatalf("Failed to get link KprobeMulti extra info")
}
qt.Assert(t, qt.IsTrue(len(kmulti.Addrs) == 0))
case sys.BPF_LINK_TYPE_PERF_EVENT:
pevent := info.PerfEvent()
switch pevent.Type {
case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE:
kprobe := pevent.Kprobe()
if kprobe.Addr == 0 {
t.Fatalf("Failed to get link Kprobe info")
}
case sys.BPF_PERF_EVENT_UPROBE, sys.BPF_PERF_EVENT_URETPROBE:
uprobe := pevent.Uprobe()
if uprobe.Offset == 0 {
t.Fatalf("Failed to get link Uprobe info")
}
case sys.BPF_PERF_EVENT_TRACEPOINT:
tp := pevent.Tracepoint()
if tp.NameLen == 0 {
t.Fatalf("Failed to get link Tracepoint info")
}
case sys.BPF_PERF_EVENT_EVENT:
event := pevent.Event()
if event.Type == 0 {
t.Fatalf("Failed to get link Event info")
}
}
}
})

Expand Down
94 changes: 94 additions & 0 deletions link/perf_event.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package link

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"runtime"
Expand Down Expand Up @@ -158,6 +160,98 @@ func (pi *perfEventIoctl) InfoOpts(_ *InfoOpts) (*Info, error) {
return nil, fmt.Errorf("perf event ioctl info: %w", ErrNotSupported)
}

type PerfEventInfo struct {
Type PerfEventInfoType
extra interface{}
}

type KprobeInfo sys.KprobeLinkInfo
type UprobeInfo sys.UprobeLinkInfo
type TracepointInfo sys.TracepointLinkInfo
type EventInfo sys.EventLinkInfo

// PerfEvent returns perf event type-specific link info.
//
// Returns nil if the type-specific link info isn't available.
func (r Info) PerfEvent() *PerfEventInfo {
e, _ := r.extra.(*PerfEventInfo)
return e
}

func (r *PerfEventInfo) Kprobe() *KprobeInfo {
e, _ := r.extra.(*KprobeInfo)
return e
}

func (r *PerfEventInfo) Uprobe() *UprobeInfo {
e, _ := r.extra.(*UprobeInfo)
return e
}

func (r *PerfEventInfo) Tracepoint() *TracepointInfo {
e, _ := r.extra.(*TracepointInfo)
return e
}

func (r *PerfEventInfo) Event() *EventInfo {
e, _ := r.extra.(*EventInfo)
return e
}

func (pl *perfEventLink) Info() (*Info, error) {
return pl.InfoOpts(&InfoOpts{})
}

func (pl *perfEventLink) InfoOpts(opts *InfoOpts) (*Info, error) {
var info sys.LinkInfo
var err error

if err = sys.ObjInfo(pl.fd, &info); err != nil {
return nil, fmt.Errorf("link info: %s", err)
}

var buf *bytes.Reader
var pevent sys.PerfEventLinkInfo

buf = bytes.NewReader(info.Extra[:])
err = binary.Read(buf, internal.NativeEndian, &pevent)
if err != nil {
return nil, fmt.Errorf("cannot read extra link info: %w", err)
}

var extra interface{}
switch pevent.Type {
case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE:
extra = &KprobeInfo{}
case sys.BPF_PERF_EVENT_UPROBE, sys.BPF_PERF_EVENT_URETPROBE:
extra = &UprobeInfo{}
case sys.BPF_PERF_EVENT_TRACEPOINT:
extra = &TracepointInfo{}
case sys.BPF_PERF_EVENT_EVENT:
extra = &EventInfo{}
}

if extra == nil {
return nil, fmt.Errorf("perf event ioctl info: %w", ErrNotSupported)
}

buf = bytes.NewReader(pevent.Extra[:])
err = binary.Read(buf, internal.NativeEndian, extra)
if err != nil {
return nil, fmt.Errorf("cannot read extra link info: %w", err)
}

return &Info{
info.Type,
info.Id,
ebpf.ProgramID(info.ProgId),
&PerfEventInfo{
pevent.Type,
extra,
},
}, nil
}

// attach the given eBPF prog to the perf event stored in pe.
// pe must contain a valid perf event fd.
// prog's type must match the program type stored in pe.
Expand Down

0 comments on commit ecb4d92

Please sign in to comment.