From 0460442cba15adcf37ae6c026817b15d403ce31b Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Fri, 12 Jul 2024 18:43:34 +0200 Subject: [PATCH] internal: add dlsym package for working with dynamically loaded symbols The dlsym package provides LookupSymbol() which resolves a named symbol (like "rbd_clone4") and returns a unsafe.Pointer to it. The caller is expected to cast the symbol to function that can be called. Signed-off-by: Niels de Vos --- internal/dlsym/dlsym.go | 41 ++++++++++++++++++++++++++++++++++++ internal/dlsym/dlsym_test.go | 22 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 internal/dlsym/dlsym.go create mode 100644 internal/dlsym/dlsym_test.go diff --git a/internal/dlsym/dlsym.go b/internal/dlsym/dlsym.go new file mode 100644 index 0000000..9e5782c --- /dev/null +++ b/internal/dlsym/dlsym.go @@ -0,0 +1,41 @@ +package dlsym + +// #cgo LDFLAGS: -ldl +// +// #include +// #include +// +// #ifndef RTLD_DEFAULT /* from dlfcn.h */ +// #define RTLD_DEFAULT ((void *) 0) +// #endif +import "C" + +import ( + "errors" + "fmt" + "unsafe" +) + +// ErrUndefinedSymbol is returned by LookupSymbol when the requested symbol +// could not be found. +var ErrUndefinedSymbol = errors.New("symbol not found") + +// LookupSymbol resolves the named symbol from the already dynamically loaded +// libraries. If the symbol is found, a pointer to it is returned, in case of a +// failure, the message provided by dlerror() is included in the error message. +func LookupSymbol(symbol string) (unsafe.Pointer, error) { + cSymName := C.CString(symbol) + defer C.free(unsafe.Pointer(cSymName)) + + // clear dlerror before looking up the symbol + C.dlerror() + // resolve the address of the symbol + sym := C.dlsym(C.RTLD_DEFAULT, cSymName) + e := C.dlerror() + dlerr := C.GoString(e) + if dlerr != "" { + return nil, fmt.Errorf("%w: %s", ErrUndefinedSymbol, dlerr) + } + + return sym, nil +} diff --git a/internal/dlsym/dlsym_test.go b/internal/dlsym/dlsym_test.go new file mode 100644 index 0000000..c33eccc --- /dev/null +++ b/internal/dlsym/dlsym_test.go @@ -0,0 +1,22 @@ +package dlsym + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLookupSymbol(t *testing.T) { + t.Run("ValidSymbol", func(t *testing.T) { + sym, err := LookupSymbol("dlsym") + assert.NotNil(t, sym) + assert.NoError(t, err) + }) + + t.Run("InvalidSymbol", func(t *testing.T) { + sym, err := LookupSymbol("go_ceph_dlsym") + assert.Nil(t, sym) + assert.True(t, errors.Is(err, ErrUndefinedSymbol)) + }) +}