func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
	return tracefsProbe(uprobeType, symbol, path, offset, ret)
}
tracefsUprobe creates a Uprobe tracefs entry.
package link
import (
	"debug/elf"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"sync"
	"github.com/cilium/ebpf"
	"github.com/cilium/ebpf/internal"
)
var (
	uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events")
	rgxUprobeSymbol = regexp.MustCompile("[^a-zA-Z0-9]+")
	uprobeRetprobeBit = struct {
		once  sync.Once
		value uint64
		err   error
	}{}
)
type Executable struct {
	path string
	symbols map[string]elf.Symbol
}
type UprobeOptions struct {
	Offset uint64
}
func OpenExecutable(path string) (*Executable, error) {
	if path == "" {
		return nil, fmt.Errorf("path cannot be empty")
	}
	f, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("open file '%s': %w", path, err)
	}
	defer f.Close()
	se, err := internal.NewSafeELFFile(f)
	if err != nil {
		return nil, fmt.Errorf("parse ELF file: %w", err)
	}
	var ex = Executable{
		path:    path,
		symbols: make(map[string]elf.Symbol),
	}
	if err := ex.addSymbols(se.Symbols); err != nil {
		return nil, err
	}
	if err := ex.addSymbols(se.DynamicSymbols); err != nil {
		return nil, err
	}
	return &ex, nil
}
func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error {
	syms, err := f()
	if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
		return err
	}
	for _, s := range syms {
		if elf.ST_TYPE(s.Info) != elf.STT_FUNC {
			continue
		}
		ex.symbols[s.Name] = s
	}
	return nil
}
func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
	if s, ok := ex.symbols[symbol]; ok {
		return &s, nil
	}
	return nil, fmt.Errorf("symbol %s not found", symbol)
}
func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
	u, err := ex.uprobe(symbol, prog, opts, false)
	if err != nil {
		return nil, err
	}
	err = u.attach(prog)
	if err != nil {
		u.Close()
		return nil, err
	}
	return u, nil
}
func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
	u, err := ex.uprobe(symbol, prog, opts, true)
	if err != nil {
		return nil, err
	}
	err = u.attach(prog)
	if err != nil {
		u.Close()
		return nil, err
	}
	return u, nil
}
func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions, ret bool) (*perfEvent, error) {
	if prog == nil {
		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
	}
	if prog.Type() != ebpf.Kprobe {
		return nil, fmt.Errorf("eBPF program type %s is not Kprobe: %w", prog.Type(), errInvalidInput)
	}
	var offset uint64
	if opts != nil && opts.Offset != 0 {
		offset = opts.Offset
	} else {
		sym, err := ex.symbol(symbol)
		if err != nil {
			return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, err)
		}
		if sym.Section == elf.SHN_UNDEF && sym.Value == 0 {
			return nil, fmt.Errorf("cannot resolve %s library call '%s', "+
				"consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported)
		}
		offset = sym.Value
	}
	tp, err := pmuUprobe(symbol, ex.path, offset, ret)
	if err == nil {
		return tp, nil
	}
	if err != nil && !errors.Is(err, ErrNotSupported) {
		return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err)
	}
	tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, ret)
	if err != nil {
		return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err)
	}
	return tp, nil
}
func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
	return pmuProbe(uprobeType, symbol, path, offset, ret)
}