Skip to content

Commit

Permalink
Add GetBpfHelpers() API
Browse files Browse the repository at this point in the history
This commit adds a new API GetBpfHelpers(), which accepts symbols (from
/proc/kallsyms) and returns all bpf helper names used at present.

The idea is to scan assembly code of each bpf functions (has
suffix [bpf]) and gather all callees, which are bpf helpers.

The steps are like:

1. Get all bpf progs:

```
 # cat /proc/kallsyms | grep '\[bpf\]$'
[...]
ffffffffc0380af8 t bpf_prog_3cdf7f3879992857_tail_ipv4_to_endpoint	[bpf]
ffffffffc0382514 t bpf_prog_e214e82dc4b46fca_cil_from_container	[bpf]
ffffffffc0382870 t bpf_prog_773159d28c0ab73a_cil_to_container	[bpf]
[...]
```

2. Get all callee addresses from each bpf prog:

```
 # gdb -ex 'x/5000i 0xffffffffc0382870' -ex q vmlinux /proc/kcore | grep call
[...]
   0xffffffffc03829ee:	call   0xffffffff9fb2ee50
   0xffffffffc0382a47:	call   0xffffffff9fb2fd20
   0xffffffffc0382ad4:	call   0xffffffffa0649120
[...]
```

3. Convert addresses to symbols

```
 # cat /proc/kallsyms | grep ffffffff9fb2ee50
ffffffff9fb2ee50 t htab_percpu_map_lookup_elem
```

Currently only x64 are taken care of.

Signed-off-by: gray <gray.liang@isovalent.com>
  • Loading branch information
jschwinger233 authored and brb committed Sep 2, 2024
1 parent 2893168 commit fc7e097
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
70 changes: 70 additions & 0 deletions internal/asm/x86/x86.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package x86

import (
"debug/elf"
"fmt"
"log"
"os"

"golang.org/x/arch/x86/x86asm"
)

var (
kcore *os.File
kcoreElf *elf.File
)

func init() {
var err error
if kcore, err = os.Open("/proc/kcore"); err != nil {
log.Fatalf("failed to open /proc/kcore: %s", err)
}
if kcoreElf, err = elf.NewFile(kcore); err != nil {
log.Fatalf("failed to new kcore elf: %s", err)
}

}

func GetCallees(addr uint64, leng int) (callees []uint64, err error) {
if leng == 0 {
leng = 100000
}
for _, prog := range kcoreElf.Progs {
if prog.Vaddr <= addr && prog.Vaddr+prog.Memsz >= addr {
bytes := make([]byte, leng)
if _, err = kcore.ReadAt(bytes, int64(prog.Off+addr-prog.Vaddr)); err != nil {
fmt.Println(err)
}
if len(bytes) == 0 {
continue
}
off := 0
for {
inst, err := x86asm.Decode(bytes, 64)
if err != nil {
inst = x86asm.Inst{Len: 1}
off += 1
}
if inst.Op == x86asm.CALL {
for _, arg := range inst.Args {
if arg == nil {
break
}
rel, ok := arg.(x86asm.Rel)
if !ok {
break
}
callees = append(callees, addr+uint64(off)+uint64(rel)+uint64(inst.Len))
}
}
bytes = bytes[inst.Len:]
off += inst.Len
if len(bytes) == 0 {
break
}
}
}
}

return
}
29 changes: 29 additions & 0 deletions internal/pwru/asm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package pwru

import (
"strings"

"github.com/cilium/pwru/internal/asm/x86"
)

func GetBpfHelpers(addr2name Addr2Name) (helpers []string, err error) {
total := len(addr2name.Addr2NameSlice)
for idx, ksym := range addr2name.Addr2NameSlice {
if strings.HasSuffix(ksym.name, "[bpf]") {
leng := 0
if idx < total-1 {
leng = int(addr2name.Addr2NameSlice[idx+1].addr - ksym.addr)
}
callees, err := x86.GetCallees(ksym.addr, leng)
if err != nil {
return nil, err
}
for _, calleeAddr := range callees {
if name, ok := addr2name.Addr2NameMap[calleeAddr]; ok {
helpers = append(helpers, name.name)
}
}
}
}
return
}

0 comments on commit fc7e097

Please sign in to comment.