Skip to content

Commit

Permalink
fixup! link: implement uprobe_multi link type
Browse files Browse the repository at this point in the history
Align UprobeMulti with Uprobe semantics for symbols, addresses and offsets.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
  • Loading branch information
lmb committed Jan 23, 2024
1 parent cee9efb commit 9830564
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 53 deletions.
16 changes: 8 additions & 8 deletions link/uprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ var (
type Executable struct {
// Path of the executable on the filesystem.
path string
// Parsed ELF and dynamic symbols' addresses.
addresses map[string]uint64
// Parsed ELF and dynamic symbols' cachedAddresses.
cachedAddresses map[string]uint64
// Keep track of symbol table lazy load.
addressesOnce sync.Once
cacheAddressesOnce sync.Once
}

// UprobeOptions defines additional parameters that will be used
Expand Down Expand Up @@ -108,8 +108,8 @@ func OpenExecutable(path string) (*Executable, error) {
}

return &Executable{
path: path,
addresses: make(map[string]uint64),
path: path,
cachedAddresses: make(map[string]uint64),
}, nil
}

Expand Down Expand Up @@ -153,7 +153,7 @@ func (ex *Executable) load(f *internal.SafeELFFile) error {
}
}

ex.addresses[s.Name] = address
ex.cachedAddresses[s.Name] = address
}

return nil
Expand All @@ -168,7 +168,7 @@ func (ex *Executable) address(symbol string, address, offset uint64) (uint64, er
}

var err error
ex.addressesOnce.Do(func() {
ex.cacheAddressesOnce.Do(func() {
var f *internal.SafeELFFile
f, err = internal.OpenSafeELFFile(ex.path)
if err != nil {
Expand All @@ -183,7 +183,7 @@ func (ex *Executable) address(symbol string, address, offset uint64) (uint64, er
return 0, fmt.Errorf("lazy load symbols: %w", err)
}

address, ok := ex.addresses[symbol]
address, ok := ex.cachedAddresses[symbol]
if !ok {
return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol)
}
Expand Down
78 changes: 36 additions & 42 deletions link/uprobe_multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *Up
opts = &UprobeMultiOptions{}
}

err := ex.uprobeMultiResolve(symbols, opts)
addresses, err := ex.addresses(symbols, opts.Addresses, opts.Offsets)
if err != nil {
return nil, err
}

addrs := len(opts.Addresses)
addrs := len(addresses)
cookies := len(opts.Cookies)
refCtrOffsets := len(opts.RefCtrOffsets)

Expand Down Expand Up @@ -114,59 +114,53 @@ func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *Up
return &uprobeMultiLink{RawLink{fd, ""}}, nil
}

// uprobeMultiResolve resolves symbols (with optional opts.Offsets) and
// computes opts.Addresses.
//
// opts must not be nil.
func (ex *Executable) uprobeMultiResolve(symbols []string, opts *UprobeMultiOptions) error {
func (ex *Executable) addresses(symbols []string, addresses, offsets []uint64) ([]uint64, error) {
n := len(symbols)
if n == 0 {
n = len(addresses)
}

// We have either opts.Addresses array with absolute file offsets
// or we need to get from symbols array and optional opts.Offsets.
syms := len(symbols)
addrs := len(opts.Addresses)
offsets := len(opts.Offsets)
if n == 0 {
return nil, fmt.Errorf("%w: neither symbols nor addresses given", errInvalidInput)
}

if addrs != 0 && syms != 0 {
return fmt.Errorf("Addresses and symbols are mutually exclusive: %w", errInvalidInput)
if symbols != nil && len(symbols) != n {
return nil, fmt.Errorf("%w: have %d symbols but want %d", errInvalidInput, len(symbols), n)
}

off := func(idx int) uint64 {
if offsets != 0 {
return opts.Offsets[idx]
}
return 0
if addresses != nil && len(addresses) != n {
return nil, fmt.Errorf("%w: have %d addresses but want %d", errInvalidInput, len(addresses), n)
}

// We either need to resolve symbols..
if syms != 0 {
if offsets != 0 && offsets != syms {
return fmt.Errorf("Offsets must be either zero or exactly symbols in length: %w", errInvalidInput)
}
for idx, symbol := range symbols {
address, err := ex.address(symbol, 0, off(idx))
if err != nil {
return err
}
opts.Addresses = append(opts.Addresses, address)
}
return nil
if offsets != nil && len(offsets) != n {
return nil, fmt.Errorf("%w: have %d offsets but want %d", errInvalidInput, len(offsets), n)
}

// ..or we were given symbol addresses
if addrs != 0 {
if offsets == 0 {
return nil
results := make([]uint64, 0, n)
for i := 0; i < n; i++ {
var sym string
if symbols != nil {
sym = symbols[i]
}
if offsets != addrs {
return fmt.Errorf("Offsets must be either zero or exactly Addresses in length: %w", errInvalidInput)

var addr, off uint64
if addresses != nil {
addr = addresses[i]
}
for idx, address := range opts.Addresses {
opts.Addresses[idx] = address + off(idx)

if offsets != nil {
off = offsets[i]
}
return nil

result, err := ex.address(sym, addr, off)
if err != nil {
return nil, err
}

results = append(results, result)
}

return fmt.Errorf("Addresses or symbols must be specified: %w", errInvalidInput)
return results, nil
}

type uprobeMultiLink struct {
Expand Down
6 changes: 3 additions & 3 deletions link/uprobe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestExecutableLazyLoadSymbols(t *testing.T) {
ex, err := OpenExecutable("/bin/bash")
qt.Assert(t, qt.IsNil(err))
// Addresses must be empty, will be lazy loaded.
qt.Assert(t, qt.HasLen(ex.addresses, 0))
qt.Assert(t, qt.HasLen(ex.cachedAddresses, 0))

prog := mustLoadProgram(t, ebpf.Kprobe, 0, "")
// Address must be a multiple of 4 on arm64, see
Expand All @@ -82,14 +82,14 @@ func TestExecutableLazyLoadSymbols(t *testing.T) {
up.Close()

// Addresses must still be empty as Address has been provided via options.
qt.Assert(t, qt.HasLen(ex.addresses, 0))
qt.Assert(t, qt.HasLen(ex.cachedAddresses, 0))

up, err = ex.Uprobe(bashSym, prog, nil)
qt.Assert(t, qt.IsNil(err))
up.Close()

// Symbol table should be loaded.
qt.Assert(t, qt.Not(qt.HasLen(ex.addresses, 0)))
qt.Assert(t, qt.Not(qt.HasLen(ex.cachedAddresses, 0)))
}

func TestUprobe(t *testing.T) {
Expand Down

0 comments on commit 9830564

Please sign in to comment.