mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-31 07:09:48 +07:00
optimize: lower kernel version requirement from 5.6 to 5.2
This commit is contained in:
8
pkg/ebpf_internal/align.go
Normal file
8
pkg/ebpf_internal/align.go
Normal file
@ -0,0 +1,8 @@
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/align.go
|
||||
|
||||
package internal
|
||||
|
||||
// Align returns 'n' updated to 'alignment' boundary.
|
||||
func Align(n, alignment int) int {
|
||||
return (int(n) + alignment - 1) / alignment * alignment
|
||||
}
|
104
pkg/ebpf_internal/elf.go
Normal file
104
pkg/ebpf_internal/elf.go
Normal file
@ -0,0 +1,104 @@
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/elf.go
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type SafeELFFile struct {
|
||||
*elf.File
|
||||
}
|
||||
|
||||
// NewSafeELFFile reads an ELF safely.
|
||||
//
|
||||
// Any panic during parsing is turned into an error. This is necessary since
|
||||
// there are a bunch of unfixed bugs in debug/elf.
|
||||
//
|
||||
// https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+debug%2Felf+in%3Atitle
|
||||
func NewSafeELFFile(r io.ReaderAt) (safe *SafeELFFile, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
safe = nil
|
||||
err = fmt.Errorf("reading ELF file panicked: %s", r)
|
||||
}()
|
||||
|
||||
file, err := elf.NewFile(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SafeELFFile{file}, nil
|
||||
}
|
||||
|
||||
// OpenSafeELFFile reads an ELF from a file.
|
||||
//
|
||||
// It works like NewSafeELFFile, with the exception that safe.Close will
|
||||
// close the underlying file.
|
||||
func OpenSafeELFFile(path string) (safe *SafeELFFile, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
safe = nil
|
||||
err = fmt.Errorf("reading ELF file panicked: %s", r)
|
||||
}()
|
||||
|
||||
file, err := elf.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SafeELFFile{file}, nil
|
||||
}
|
||||
|
||||
// Symbols is the safe version of elf.File.Symbols.
|
||||
func (se *SafeELFFile) Symbols() (syms []elf.Symbol, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
syms = nil
|
||||
err = fmt.Errorf("reading ELF symbols panicked: %s", r)
|
||||
}()
|
||||
|
||||
syms, err = se.File.Symbols()
|
||||
return
|
||||
}
|
||||
|
||||
// DynamicSymbols is the safe version of elf.File.DynamicSymbols.
|
||||
func (se *SafeELFFile) DynamicSymbols() (syms []elf.Symbol, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
syms = nil
|
||||
err = fmt.Errorf("reading ELF dynamic symbols panicked: %s", r)
|
||||
}()
|
||||
|
||||
syms, err = se.File.DynamicSymbols()
|
||||
return
|
||||
}
|
||||
|
||||
// SectionsByType returns all sections in the file with the specified section type.
|
||||
func (se *SafeELFFile) SectionsByType(typ elf.SectionType) []*elf.Section {
|
||||
sections := make([]*elf.Section, 0, 1)
|
||||
for _, section := range se.Sections {
|
||||
if section.Type == typ {
|
||||
sections = append(sections, section)
|
||||
}
|
||||
}
|
||||
return sections
|
||||
}
|
15
pkg/ebpf_internal/endian_be.go
Normal file
15
pkg/ebpf_internal/endian_be.go
Normal file
@ -0,0 +1,15 @@
|
||||
//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64
|
||||
// +build armbe arm64be mips mips64 mips64p32 ppc64 s390 s390x sparc sparc64
|
||||
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/endian_be.go
|
||||
|
||||
package internal
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// NativeEndian is set to either binary.BigEndian or binary.LittleEndian,
|
||||
// depending on the host's endianness.
|
||||
var NativeEndian binary.ByteOrder = binary.BigEndian
|
||||
|
||||
// ClangEndian is set to either "el" or "eb" depending on the host's endianness.
|
||||
const ClangEndian = "eb"
|
15
pkg/ebpf_internal/endian_le.go
Normal file
15
pkg/ebpf_internal/endian_le.go
Normal file
@ -0,0 +1,15 @@
|
||||
//go:build 386 || amd64 || amd64p32 || arm || arm64 || mipsle || mips64le || mips64p32le || ppc64le || riscv64
|
||||
// +build 386 amd64 amd64p32 arm arm64 mipsle mips64le mips64p32le ppc64le riscv64
|
||||
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/endian_le.go
|
||||
|
||||
package internal
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// NativeEndian is set to either binary.BigEndian or binary.LittleEndian,
|
||||
// depending on the host's endianness.
|
||||
var NativeEndian binary.ByteOrder = binary.LittleEndian
|
||||
|
||||
// ClangEndian is set to either "el" or "eb" depending on the host's endianness.
|
||||
const ClangEndian = "el"
|
13
pkg/ebpf_internal/internal/unix/doc.go
Normal file
13
pkg/ebpf_internal/internal/unix/doc.go
Normal file
@ -0,0 +1,13 @@
|
||||
// Copied from https://github.com/cilium/ebpf/tree/v0.10.0/internal/unix
|
||||
|
||||
// Package unix re-exports Linux specific parts of golang.org/x/sys/unix.
|
||||
//
|
||||
// It avoids breaking compilation on other OS by providing stubs as follows:
|
||||
// - Invoking a function always returns an error.
|
||||
// - Errnos have distinct, non-zero values.
|
||||
// - Constants have distinct but meaningless values.
|
||||
// - Types use the same names for members, but may or may not follow the
|
||||
// Linux layout.
|
||||
package unix
|
||||
|
||||
// Note: please don't add any custom API to this package. Use internal/sys instead.
|
192
pkg/ebpf_internal/internal/unix/types_linux.go
Normal file
192
pkg/ebpf_internal/internal/unix/types_linux.go
Normal file
@ -0,0 +1,192 @@
|
||||
//go:build linux
|
||||
|
||||
// Copied from https://github.com/cilium/ebpf/tree/v0.10.0/internal/unix
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
linux "golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
ENOENT = linux.ENOENT
|
||||
EEXIST = linux.EEXIST
|
||||
EAGAIN = linux.EAGAIN
|
||||
ENOSPC = linux.ENOSPC
|
||||
EINVAL = linux.EINVAL
|
||||
EPOLLIN = linux.EPOLLIN
|
||||
EINTR = linux.EINTR
|
||||
EPERM = linux.EPERM
|
||||
ESRCH = linux.ESRCH
|
||||
ENODEV = linux.ENODEV
|
||||
EBADF = linux.EBADF
|
||||
E2BIG = linux.E2BIG
|
||||
EFAULT = linux.EFAULT
|
||||
EACCES = linux.EACCES
|
||||
EILSEQ = linux.EILSEQ
|
||||
EOPNOTSUPP = linux.EOPNOTSUPP
|
||||
)
|
||||
|
||||
const (
|
||||
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
|
||||
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
|
||||
BPF_F_RDONLY = linux.BPF_F_RDONLY
|
||||
BPF_F_WRONLY = linux.BPF_F_WRONLY
|
||||
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
|
||||
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
|
||||
BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE
|
||||
BPF_F_MMAPABLE = linux.BPF_F_MMAPABLE
|
||||
BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP
|
||||
BPF_F_KPROBE_MULTI_RETURN = linux.BPF_F_KPROBE_MULTI_RETURN
|
||||
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
||||
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
||||
BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT
|
||||
BPF_RINGBUF_DISCARD_BIT = linux.BPF_RINGBUF_DISCARD_BIT
|
||||
BPF_RINGBUF_HDR_SZ = linux.BPF_RINGBUF_HDR_SZ
|
||||
SYS_BPF = linux.SYS_BPF
|
||||
F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC
|
||||
EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD
|
||||
EPOLL_CLOEXEC = linux.EPOLL_CLOEXEC
|
||||
O_CLOEXEC = linux.O_CLOEXEC
|
||||
O_NONBLOCK = linux.O_NONBLOCK
|
||||
PROT_READ = linux.PROT_READ
|
||||
PROT_WRITE = linux.PROT_WRITE
|
||||
MAP_SHARED = linux.MAP_SHARED
|
||||
PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1
|
||||
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
|
||||
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
|
||||
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
|
||||
PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE
|
||||
PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE
|
||||
PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF
|
||||
PerfBitWatermark = linux.PerfBitWatermark
|
||||
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
||||
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
||||
RLIM_INFINITY = linux.RLIM_INFINITY
|
||||
RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK
|
||||
BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME
|
||||
PERF_RECORD_LOST = linux.PERF_RECORD_LOST
|
||||
PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE
|
||||
AT_FDCWD = linux.AT_FDCWD
|
||||
RENAME_NOREPLACE = linux.RENAME_NOREPLACE
|
||||
SO_ATTACH_BPF = linux.SO_ATTACH_BPF
|
||||
SO_DETACH_BPF = linux.SO_DETACH_BPF
|
||||
SOL_SOCKET = linux.SOL_SOCKET
|
||||
SIGPROF = linux.SIGPROF
|
||||
SIG_BLOCK = linux.SIG_BLOCK
|
||||
SIG_UNBLOCK = linux.SIG_UNBLOCK
|
||||
EM_NONE = linux.EM_NONE
|
||||
EM_BPF = linux.EM_BPF
|
||||
)
|
||||
|
||||
type Statfs_t = linux.Statfs_t
|
||||
type Stat_t = linux.Stat_t
|
||||
type Rlimit = linux.Rlimit
|
||||
type Signal = linux.Signal
|
||||
type Sigset_t = linux.Sigset_t
|
||||
type PerfEventMmapPage = linux.PerfEventMmapPage
|
||||
type EpollEvent = linux.EpollEvent
|
||||
type PerfEventAttr = linux.PerfEventAttr
|
||||
type Utsname = linux.Utsname
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return linux.Syscall(trap, a1, a2, a3)
|
||||
}
|
||||
|
||||
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
||||
return linux.PthreadSigmask(how, set, oldset)
|
||||
}
|
||||
|
||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
return linux.FcntlInt(fd, cmd, arg)
|
||||
}
|
||||
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
return linux.IoctlSetInt(fd, req, value)
|
||||
}
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
return linux.Statfs(path, buf)
|
||||
}
|
||||
|
||||
func Close(fd int) (err error) {
|
||||
return linux.Close(fd)
|
||||
}
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
return linux.EpollWait(epfd, events, msec)
|
||||
}
|
||||
|
||||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||
return linux.EpollCtl(epfd, op, fd, event)
|
||||
}
|
||||
|
||||
func Eventfd(initval uint, flags int) (fd int, err error) {
|
||||
return linux.Eventfd(initval, flags)
|
||||
}
|
||||
|
||||
func Write(fd int, p []byte) (n int, err error) {
|
||||
return linux.Write(fd, p)
|
||||
}
|
||||
|
||||
func EpollCreate1(flag int) (fd int, err error) {
|
||||
return linux.EpollCreate1(flag)
|
||||
}
|
||||
|
||||
func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||
return linux.SetNonblock(fd, nonblocking)
|
||||
}
|
||||
|
||||
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
||||
return linux.Mmap(fd, offset, length, prot, flags)
|
||||
}
|
||||
|
||||
func Munmap(b []byte) (err error) {
|
||||
return linux.Munmap(b)
|
||||
}
|
||||
|
||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||
return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags)
|
||||
}
|
||||
|
||||
func Uname(buf *Utsname) (err error) {
|
||||
return linux.Uname(buf)
|
||||
}
|
||||
|
||||
func Getpid() int {
|
||||
return linux.Getpid()
|
||||
}
|
||||
|
||||
func Gettid() int {
|
||||
return linux.Gettid()
|
||||
}
|
||||
|
||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return linux.Tgkill(tgid, tid, sig)
|
||||
}
|
||||
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
return linux.BytePtrFromString(s)
|
||||
}
|
||||
|
||||
func ByteSliceToString(s []byte) string {
|
||||
return linux.ByteSliceToString(s)
|
||||
}
|
||||
|
||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||
return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags)
|
||||
}
|
||||
|
||||
func Prlimit(pid, resource int, new, old *Rlimit) error {
|
||||
return linux.Prlimit(pid, resource, new, old)
|
||||
}
|
||||
|
||||
func Open(path string, mode int, perm uint32) (int, error) {
|
||||
return linux.Open(path, mode, perm)
|
||||
}
|
||||
|
||||
func Fstat(fd int, stat *Stat_t) error {
|
||||
return linux.Fstat(fd, stat)
|
||||
}
|
272
pkg/ebpf_internal/internal/unix/types_other.go
Normal file
272
pkg/ebpf_internal/internal/unix/types_other.go
Normal file
@ -0,0 +1,272 @@
|
||||
//go:build !linux
|
||||
|
||||
// Copied from https://github.com/cilium/ebpf/tree/v0.10.0/internal/unix
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
// Errnos are distinct and non-zero.
|
||||
const (
|
||||
ENOENT syscall.Errno = iota + 1
|
||||
EEXIST
|
||||
EAGAIN
|
||||
ENOSPC
|
||||
EINVAL
|
||||
EINTR
|
||||
EPERM
|
||||
ESRCH
|
||||
ENODEV
|
||||
EBADF
|
||||
E2BIG
|
||||
EFAULT
|
||||
EACCES
|
||||
EILSEQ
|
||||
EOPNOTSUPP
|
||||
)
|
||||
|
||||
// Constants are distinct to avoid breaking switch statements.
|
||||
const (
|
||||
BPF_F_NO_PREALLOC = iota
|
||||
BPF_F_NUMA_NODE
|
||||
BPF_F_RDONLY
|
||||
BPF_F_WRONLY
|
||||
BPF_F_RDONLY_PROG
|
||||
BPF_F_WRONLY_PROG
|
||||
BPF_F_SLEEPABLE
|
||||
BPF_F_MMAPABLE
|
||||
BPF_F_INNER_MAP
|
||||
BPF_F_KPROBE_MULTI_RETURN
|
||||
BPF_OBJ_NAME_LEN
|
||||
BPF_TAG_SIZE
|
||||
BPF_RINGBUF_BUSY_BIT
|
||||
BPF_RINGBUF_DISCARD_BIT
|
||||
BPF_RINGBUF_HDR_SZ
|
||||
SYS_BPF
|
||||
F_DUPFD_CLOEXEC
|
||||
EPOLLIN
|
||||
EPOLL_CTL_ADD
|
||||
EPOLL_CLOEXEC
|
||||
O_CLOEXEC
|
||||
O_NONBLOCK
|
||||
PROT_READ
|
||||
PROT_WRITE
|
||||
MAP_SHARED
|
||||
PERF_ATTR_SIZE_VER1
|
||||
PERF_TYPE_SOFTWARE
|
||||
PERF_TYPE_TRACEPOINT
|
||||
PERF_COUNT_SW_BPF_OUTPUT
|
||||
PERF_EVENT_IOC_DISABLE
|
||||
PERF_EVENT_IOC_ENABLE
|
||||
PERF_EVENT_IOC_SET_BPF
|
||||
PerfBitWatermark
|
||||
PERF_SAMPLE_RAW
|
||||
PERF_FLAG_FD_CLOEXEC
|
||||
RLIM_INFINITY
|
||||
RLIMIT_MEMLOCK
|
||||
BPF_STATS_RUN_TIME
|
||||
PERF_RECORD_LOST
|
||||
PERF_RECORD_SAMPLE
|
||||
AT_FDCWD
|
||||
RENAME_NOREPLACE
|
||||
SO_ATTACH_BPF
|
||||
SO_DETACH_BPF
|
||||
SOL_SOCKET
|
||||
SIGPROF
|
||||
SIG_BLOCK
|
||||
SIG_UNBLOCK
|
||||
EM_NONE
|
||||
EM_BPF
|
||||
)
|
||||
|
||||
type Statfs_t struct {
|
||||
Type int64
|
||||
Bsize int64
|
||||
Blocks uint64
|
||||
Bfree uint64
|
||||
Bavail uint64
|
||||
Files uint64
|
||||
Ffree uint64
|
||||
Fsid [2]int32
|
||||
Namelen int64
|
||||
Frsize int64
|
||||
Flags int64
|
||||
Spare [4]int64
|
||||
}
|
||||
|
||||
type Stat_t struct{}
|
||||
|
||||
type Rlimit struct {
|
||||
Cur uint64
|
||||
Max uint64
|
||||
}
|
||||
|
||||
type Signal int
|
||||
|
||||
type Sigset_t struct {
|
||||
Val [4]uint64
|
||||
}
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return 0, 0, syscall.ENOTSUP
|
||||
}
|
||||
|
||||
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
return -1, errNonLinux
|
||||
}
|
||||
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Close(fd int) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
type EpollEvent struct {
|
||||
Events uint32
|
||||
Fd int32
|
||||
Pad int32
|
||||
}
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
return 0, errNonLinux
|
||||
}
|
||||
|
||||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Eventfd(initval uint, flags int) (fd int, err error) {
|
||||
return 0, errNonLinux
|
||||
}
|
||||
|
||||
func Write(fd int, p []byte) (n int, err error) {
|
||||
return 0, errNonLinux
|
||||
}
|
||||
|
||||
func EpollCreate1(flag int) (fd int, err error) {
|
||||
return 0, errNonLinux
|
||||
}
|
||||
|
||||
type PerfEventMmapPage struct {
|
||||
Version uint32
|
||||
Compat_version uint32
|
||||
Lock uint32
|
||||
Index uint32
|
||||
Offset int64
|
||||
Time_enabled uint64
|
||||
Time_running uint64
|
||||
Capabilities uint64
|
||||
Pmc_width uint16
|
||||
Time_shift uint16
|
||||
Time_mult uint32
|
||||
Time_offset uint64
|
||||
Time_zero uint64
|
||||
Size uint32
|
||||
|
||||
Data_head uint64
|
||||
Data_tail uint64
|
||||
Data_offset uint64
|
||||
Data_size uint64
|
||||
Aux_head uint64
|
||||
Aux_tail uint64
|
||||
Aux_offset uint64
|
||||
Aux_size uint64
|
||||
}
|
||||
|
||||
func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
||||
return []byte{}, errNonLinux
|
||||
}
|
||||
|
||||
func Munmap(b []byte) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
type PerfEventAttr struct {
|
||||
Type uint32
|
||||
Size uint32
|
||||
Config uint64
|
||||
Sample uint64
|
||||
Sample_type uint64
|
||||
Read_format uint64
|
||||
Bits uint64
|
||||
Wakeup uint32
|
||||
Bp_type uint32
|
||||
Ext1 uint64
|
||||
Ext2 uint64
|
||||
Branch_sample_type uint64
|
||||
Sample_regs_user uint64
|
||||
Sample_stack_user uint32
|
||||
Clockid int32
|
||||
Sample_regs_intr uint64
|
||||
Aux_watermark uint32
|
||||
Sample_max_stack uint16
|
||||
}
|
||||
|
||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||
return 0, errNonLinux
|
||||
}
|
||||
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
Version [65]byte
|
||||
}
|
||||
|
||||
func Uname(buf *Utsname) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Getpid() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func Gettid() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
return nil, errNonLinux
|
||||
}
|
||||
|
||||
func ByteSliceToString(s []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Prlimit(pid, resource int, new, old *Rlimit) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func Open(path string, mode int, perm uint32) (int, error) {
|
||||
return -1, errNonLinux
|
||||
}
|
||||
|
||||
func Fstat(fd int, stat *Stat_t) error {
|
||||
return errNonLinux
|
||||
}
|
155
pkg/ebpf_internal/vdso.go
Normal file
155
pkg/ebpf_internal/vdso.go
Normal file
@ -0,0 +1,155 @@
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/vdso.go
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/v2rayA/dae/pkg/ebpf_internal/internal/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
errAuxvNoVDSO = errors.New("no vdso address found in auxv")
|
||||
)
|
||||
|
||||
// vdsoVersion returns the LINUX_VERSION_CODE embedded in the vDSO library
|
||||
// linked into the current process image.
|
||||
func vdsoVersion() (uint32, error) {
|
||||
// Read data from the auxiliary vector, which is normally passed directly
|
||||
// to the process. Go does not expose that data, so we must read it from procfs.
|
||||
// https://man7.org/linux/man-pages/man3/getauxval.3.html
|
||||
av, err := os.Open("/proc/self/auxv")
|
||||
if errors.Is(err, unix.EACCES) {
|
||||
return 0, fmt.Errorf("opening auxv: %w (process may not be dumpable due to file capabilities)", err)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("opening auxv: %w", err)
|
||||
}
|
||||
defer av.Close()
|
||||
|
||||
vdsoAddr, err := vdsoMemoryAddress(av)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("finding vDSO memory address: %w", err)
|
||||
}
|
||||
|
||||
// Use /proc/self/mem rather than unsafe.Pointer tricks.
|
||||
mem, err := os.Open("/proc/self/mem")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("opening mem: %w", err)
|
||||
}
|
||||
defer mem.Close()
|
||||
|
||||
// Open ELF at provided memory address, as offset into /proc/self/mem.
|
||||
c, err := vdsoLinuxVersionCode(io.NewSectionReader(mem, int64(vdsoAddr), math.MaxInt64))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading linux version code: %w", err)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// vdsoMemoryAddress returns the memory address of the vDSO library
|
||||
// linked into the current process image. r is an io.Reader into an auxv blob.
|
||||
func vdsoMemoryAddress(r io.Reader) (uint64, error) {
|
||||
const (
|
||||
_AT_NULL = 0 // End of vector
|
||||
_AT_SYSINFO_EHDR = 33 // Offset to vDSO blob in process image
|
||||
)
|
||||
|
||||
// Loop through all tag/value pairs in auxv until we find `AT_SYSINFO_EHDR`,
|
||||
// the address of a page containing the virtual Dynamic Shared Object (vDSO).
|
||||
aux := struct{ Tag, Val uint64 }{}
|
||||
for {
|
||||
if err := binary.Read(r, NativeEndian, &aux); err != nil {
|
||||
return 0, fmt.Errorf("reading auxv entry: %w", err)
|
||||
}
|
||||
|
||||
switch aux.Tag {
|
||||
case _AT_SYSINFO_EHDR:
|
||||
if aux.Val != 0 {
|
||||
return aux.Val, nil
|
||||
}
|
||||
return 0, fmt.Errorf("invalid vDSO address in auxv")
|
||||
// _AT_NULL is always the last tag/val pair in the aux vector
|
||||
// and can be treated like EOF.
|
||||
case _AT_NULL:
|
||||
return 0, errAuxvNoVDSO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// format described at https://www.man7.org/linux/man-pages/man5/elf.5.html in section 'Notes (Nhdr)'
|
||||
type elfNoteHeader struct {
|
||||
NameSize int32
|
||||
DescSize int32
|
||||
Type int32
|
||||
}
|
||||
|
||||
// vdsoLinuxVersionCode returns the LINUX_VERSION_CODE embedded in
|
||||
// the ELF notes section of the binary provided by the reader.
|
||||
func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
|
||||
hdr, err := NewSafeELFFile(r)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading vDSO ELF: %w", err)
|
||||
}
|
||||
|
||||
sections := hdr.SectionsByType(elf.SHT_NOTE)
|
||||
if len(sections) == 0 {
|
||||
return 0, fmt.Errorf("no note section found in vDSO ELF")
|
||||
}
|
||||
|
||||
for _, sec := range sections {
|
||||
sr := sec.Open()
|
||||
var n elfNoteHeader
|
||||
|
||||
// Read notes until we find one named 'Linux'.
|
||||
for {
|
||||
if err := binary.Read(sr, hdr.ByteOrder, &n); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// We looked at all the notes in this section
|
||||
break
|
||||
}
|
||||
return 0, fmt.Errorf("reading note header: %w", err)
|
||||
}
|
||||
|
||||
// If a note name is defined, it follows the note header.
|
||||
var name string
|
||||
if n.NameSize > 0 {
|
||||
// Read the note name, aligned to 4 bytes.
|
||||
buf := make([]byte, Align(int(n.NameSize), 4))
|
||||
if err := binary.Read(sr, hdr.ByteOrder, &buf); err != nil {
|
||||
return 0, fmt.Errorf("reading note name: %w", err)
|
||||
}
|
||||
|
||||
// Read nul-terminated string.
|
||||
name = unix.ByteSliceToString(buf[:n.NameSize])
|
||||
}
|
||||
|
||||
// If a note descriptor is defined, it follows the name.
|
||||
// It is possible for a note to have a descriptor but not a name.
|
||||
if n.DescSize > 0 {
|
||||
// LINUX_VERSION_CODE is a uint32 value.
|
||||
if name == "Linux" && n.DescSize == 4 && n.Type == 0 {
|
||||
var version uint32
|
||||
if err := binary.Read(sr, hdr.ByteOrder, &version); err != nil {
|
||||
return 0, fmt.Errorf("reading note descriptor: %w", err)
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// Discard the note descriptor if it exists but we're not interested in it.
|
||||
if _, err := io.CopyN(io.Discard, sr, int64(Align(int(n.DescSize), 4))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no Linux note in ELF")
|
||||
}
|
124
pkg/ebpf_internal/version.go
Normal file
124
pkg/ebpf_internal/version.go
Normal file
@ -0,0 +1,124 @@
|
||||
// Copied from https://github.com/cilium/ebpf/blob/v0.10.0/internal/version.go
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/v2rayA/dae/pkg/ebpf_internal/internal/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version constant used in ELF binaries indicating that the loader needs to
|
||||
// substitute the eBPF program's version with the value of the kernel's
|
||||
// KERNEL_VERSION compile-time macro. Used for compatibility with BCC, gobpf
|
||||
// and RedSift.
|
||||
MagicKernelVersion = 0xFFFFFFFE
|
||||
)
|
||||
|
||||
var (
|
||||
kernelVersion = struct {
|
||||
once sync.Once
|
||||
version Version
|
||||
err error
|
||||
}{}
|
||||
)
|
||||
|
||||
// A Version in the form Major.Minor.Patch.
|
||||
type Version [3]uint16
|
||||
|
||||
// NewVersion creates a version from a string like "Major.Minor.Patch".
|
||||
//
|
||||
// Patch is optional.
|
||||
func NewVersion(ver string) (Version, error) {
|
||||
var major, minor, patch uint16
|
||||
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
|
||||
if n < 2 {
|
||||
return Version{}, fmt.Errorf("invalid version: %s", ver)
|
||||
}
|
||||
return Version{major, minor, patch}, nil
|
||||
}
|
||||
|
||||
// NewVersionFromCode creates a version from a LINUX_VERSION_CODE.
|
||||
func NewVersionFromCode(code uint32) Version {
|
||||
return Version{
|
||||
uint16(uint8(code >> 16)),
|
||||
uint16(uint8(code >> 8)),
|
||||
uint16(uint8(code)),
|
||||
}
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v[2] == 0 {
|
||||
return fmt.Sprintf("v%d.%d", v[0], v[1])
|
||||
}
|
||||
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
|
||||
}
|
||||
|
||||
// Less returns true if the version is less than another version.
|
||||
func (v Version) Less(other Version) bool {
|
||||
for i, a := range v {
|
||||
if a == other[i] {
|
||||
continue
|
||||
}
|
||||
return a < other[i]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unspecified returns true if the version is all zero.
|
||||
func (v Version) Unspecified() bool {
|
||||
return v[0] == 0 && v[1] == 0 && v[2] == 0
|
||||
}
|
||||
|
||||
// Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h.
|
||||
// It represents the kernel version and patch level as a single value.
|
||||
func (v Version) Kernel() uint32 {
|
||||
|
||||
// Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid
|
||||
// overflowing into PATCHLEVEL.
|
||||
// See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255").
|
||||
s := v[2]
|
||||
if s > 255 {
|
||||
s = 255
|
||||
}
|
||||
|
||||
// Truncate members to uint8 to prevent them from spilling over into
|
||||
// each other when overflowing 8 bits.
|
||||
return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
|
||||
}
|
||||
|
||||
// KernelVersion returns the version of the currently running kernel.
|
||||
func KernelVersion() (Version, error) {
|
||||
kernelVersion.once.Do(func() {
|
||||
kernelVersion.version, kernelVersion.err = detectKernelVersion()
|
||||
})
|
||||
|
||||
if kernelVersion.err != nil {
|
||||
return Version{}, kernelVersion.err
|
||||
}
|
||||
return kernelVersion.version, nil
|
||||
}
|
||||
|
||||
// detectKernelVersion returns the version of the running kernel.
|
||||
func detectKernelVersion() (Version, error) {
|
||||
vc, err := vdsoVersion()
|
||||
if err != nil {
|
||||
return Version{}, err
|
||||
}
|
||||
return NewVersionFromCode(vc), nil
|
||||
}
|
||||
|
||||
// KernelRelease returns the release string of the running kernel.
|
||||
// Its format depends on the Linux distribution and corresponds to directory
|
||||
// names in /lib/modules by convention. Some examples are 5.15.17-1-lts and
|
||||
// 4.19.0-16-amd64.
|
||||
func KernelRelease() (string, error) {
|
||||
var uname unix.Utsname
|
||||
if err := unix.Uname(&uname); err != nil {
|
||||
return "", fmt.Errorf("uname failed: %w", err)
|
||||
}
|
||||
|
||||
return unix.ByteSliceToString(uname.Release[:]), nil
|
||||
}
|
Reference in New Issue
Block a user