go.mod: github.com/opencontainers/runc v1.1.0
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
135
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
135
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
@@ -25,14 +25,18 @@ var (
|
||||
value uint64
|
||||
err error
|
||||
}{}
|
||||
|
||||
// ErrNoSymbol indicates that the given symbol was not found
|
||||
// in the ELF symbols table.
|
||||
ErrNoSymbol = errors.New("not found")
|
||||
)
|
||||
|
||||
// Executable defines an executable program on the filesystem.
|
||||
type Executable struct {
|
||||
// Path of the executable on the filesystem.
|
||||
path string
|
||||
// Parsed ELF symbols and dynamic symbols.
|
||||
symbols map[string]elf.Symbol
|
||||
// Parsed ELF symbols and dynamic symbols offsets.
|
||||
offsets map[string]uint64
|
||||
}
|
||||
|
||||
// UprobeOptions defines additional parameters that will be used
|
||||
@@ -41,6 +45,9 @@ type UprobeOptions struct {
|
||||
// Symbol offset. Must be provided in case of external symbols (shared libs).
|
||||
// If set, overrides the offset eventually parsed from the executable.
|
||||
Offset uint64
|
||||
// Only set the uprobe on the given process ID. Useful when tracing
|
||||
// shared library calls or programs that have many running instances.
|
||||
PID int
|
||||
}
|
||||
|
||||
// To open a new Executable, use:
|
||||
@@ -64,42 +71,84 @@ func OpenExecutable(path string) (*Executable, error) {
|
||||
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 se.Type != elf.ET_EXEC && se.Type != elf.ET_DYN {
|
||||
// ELF is not an executable or a shared object.
|
||||
return nil, errors.New("the given file is not an executable or a shared object")
|
||||
}
|
||||
|
||||
if err := ex.addSymbols(se.DynamicSymbols); err != nil {
|
||||
ex := Executable{
|
||||
path: path,
|
||||
offsets: make(map[string]uint64),
|
||||
}
|
||||
|
||||
if err := ex.load(se); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ex, nil
|
||||
}
|
||||
|
||||
func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error {
|
||||
// elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found.
|
||||
syms, err := f()
|
||||
func (ex *Executable) load(f *internal.SafeELFFile) error {
|
||||
syms, err := f.Symbols()
|
||||
if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
|
||||
return err
|
||||
}
|
||||
|
||||
dynsyms, err := f.DynamicSymbols()
|
||||
if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
|
||||
return err
|
||||
}
|
||||
|
||||
syms = append(syms, dynsyms...)
|
||||
|
||||
for _, s := range syms {
|
||||
if elf.ST_TYPE(s.Info) != elf.STT_FUNC {
|
||||
// Symbol not associated with a function or other executable code.
|
||||
continue
|
||||
}
|
||||
ex.symbols[s.Name] = s
|
||||
|
||||
off := s.Value
|
||||
|
||||
// Loop over ELF segments.
|
||||
for _, prog := range f.Progs {
|
||||
// Skip uninteresting segments.
|
||||
if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if prog.Vaddr <= s.Value && s.Value < (prog.Vaddr+prog.Memsz) {
|
||||
// If the symbol value is contained in the segment, calculate
|
||||
// the symbol offset.
|
||||
//
|
||||
// fn symbol offset = fn symbol VA - .text VA + .text offset
|
||||
//
|
||||
// stackoverflow.com/a/40249502
|
||||
off = s.Value - prog.Vaddr + prog.Off
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ex.offsets[s.Name] = off
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
|
||||
if s, ok := ex.symbols[symbol]; ok {
|
||||
return &s, nil
|
||||
func (ex *Executable) offset(symbol string) (uint64, error) {
|
||||
if off, ok := ex.offsets[symbol]; ok {
|
||||
// Symbols with location 0 from section undef are shared library calls and
|
||||
// are relocated before the binary is executed. Dynamic linking is not
|
||||
// implemented by the library, so mark this as unsupported for now.
|
||||
//
|
||||
// Since only offset values are stored and not elf.Symbol, if the value is 0,
|
||||
// assume it's an external symbol.
|
||||
if off == 0 {
|
||||
return 0, fmt.Errorf("cannot resolve %s library call '%s', "+
|
||||
"consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported)
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
return nil, fmt.Errorf("symbol %s not found", symbol)
|
||||
return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol)
|
||||
}
|
||||
|
||||
// Uprobe attaches the given eBPF program to a perf event that fires when the
|
||||
@@ -112,11 +161,14 @@ func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
|
||||
// When using symbols which belongs to shared libraries,
|
||||
// an offset must be provided via options:
|
||||
//
|
||||
// ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
// up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
// Losing the reference to the resulting Link (up) will close the Uprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
//
|
||||
// Functions provided by shared libraries can currently not be traced and
|
||||
// will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, opts, false)
|
||||
if err != nil {
|
||||
@@ -141,11 +193,14 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
// When using symbols which belongs to shared libraries,
|
||||
// an offset must be provided via options:
|
||||
//
|
||||
// ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
// up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
// Losing the reference to the resulting Link (up) will close the Uprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
//
|
||||
// Functions provided by shared libraries can currently not be traced and
|
||||
// will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, opts, true)
|
||||
if err != nil {
|
||||
@@ -175,24 +230,20 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
if opts != nil && opts.Offset != 0 {
|
||||
offset = opts.Offset
|
||||
} else {
|
||||
sym, err := ex.symbol(symbol)
|
||||
off, err := ex.offset(symbol)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, err)
|
||||
return nil, err
|
||||
}
|
||||
offset = off
|
||||
}
|
||||
|
||||
// Symbols with location 0 from section undef are shared library calls and
|
||||
// are relocated before the binary is executed. Dynamic linking is not
|
||||
// implemented by the library, so mark this as unsupported for now.
|
||||
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
|
||||
pid := perfAllThreads
|
||||
if opts != nil && opts.PID != 0 {
|
||||
pid = opts.PID
|
||||
}
|
||||
|
||||
// Use uprobe PMU if the kernel has it available.
|
||||
tp, err := pmuUprobe(symbol, ex.path, offset, ret)
|
||||
tp, err := pmuUprobe(symbol, ex.path, offset, pid, ret)
|
||||
if err == nil {
|
||||
return tp, nil
|
||||
}
|
||||
@@ -201,7 +252,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
}
|
||||
|
||||
// Use tracefs if uprobe PMU is missing.
|
||||
tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, ret)
|
||||
tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, pid, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err)
|
||||
}
|
||||
@@ -210,13 +261,13 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
}
|
||||
|
||||
// pmuUprobe opens a perf event based on the uprobe PMU.
|
||||
func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(uprobeType, symbol, path, offset, ret)
|
||||
func pmuUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(uprobeType, symbol, path, offset, pid, ret)
|
||||
}
|
||||
|
||||
// tracefsUprobe creates a Uprobe tracefs entry.
|
||||
func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(uprobeType, symbol, path, offset, ret)
|
||||
func tracefsUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(uprobeType, symbol, path, offset, pid, ret)
|
||||
}
|
||||
|
||||
// uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore.
|
||||
|
||||
Reference in New Issue
Block a user