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 <ndevos@ibm.com>
This commit is contained in:
Niels de Vos 2024-07-12 18:43:34 +02:00 committed by mergify[bot]
parent 9531dd692a
commit 0460442cba
2 changed files with 63 additions and 0 deletions

41
internal/dlsym/dlsym.go Normal file
View File

@ -0,0 +1,41 @@
package dlsym
// #cgo LDFLAGS: -ldl
//
// #include <stdlib.h>
// #include <dlfcn.h>
//
// #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
}

View File

@ -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))
})
}