]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
util: Add dlfcn helpers
authorLucas De Marchi <lucas.de.marchi@gmail.com>
Sat, 30 Nov 2024 06:30:53 +0000 (00:30 -0600)
committerLucas De Marchi <lucas.de.marchi@gmail.com>
Fri, 6 Dec 2024 21:05:09 +0000 (13:05 -0800)
Heavily based on systemd: add similar (but simplified) functions to
dlopen() a library and load specific symbols from it. This will be
useful to allow to load the compression libraries as needed. A few
differences from the systemd implementation:

1) It's allowed to link directly to the library and hence bypass the
   dlopen() + dlsym()
2) The only entrypoint is dlsym_many() which is already declared with
   the sentinel: it's expected callers will use an x-macro that doesn't
   allow forgetting the sentinel
3) No support yet for ELF info annotation yet

Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/262
shared/macro.h
shared/util.c
shared/util.h

index 2def79f2b6b2bbc2cc77c2643e08046ac412dd74..7b4ea4214d4b7a8a0e7586d7c162ad9f745607c9 100644 (file)
@@ -43,6 +43,7 @@
 #define _must_check_ __attribute__((warn_unused_result))
 #define _printf_format_(a, b) __attribute__((format(printf, a, b)))
 #define _always_inline_ __inline__ __attribute__((always_inline))
+#define _sentinel_ __attribute__((sentinel))
 
 #if defined(__clang_analyzer__)
 #define _clang_suppress_ __attribute__((suppress))
index 81026ca33fb803bae23409df5d5eb86f262b04fb..9a54c07efc93c30c761597e04a2626fdb4322079 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <assert.h>
 #include <ctype.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -560,3 +561,46 @@ unsigned long long stat_mstamp(const struct stat *st)
        return (unsigned long long)st->st_mtime;
 #endif
 }
+
+static int dlsym_manyv(void *dl, va_list ap)
+{
+       void (**fn)(void);
+
+       while ((fn = va_arg(ap, typeof(fn)))) {
+               const char *symbol;
+
+               symbol = va_arg(ap, typeof(symbol));
+               *fn = dlsym(dl, symbol);
+               if (!*fn)
+                       return -ENXIO;
+       }
+
+       return 0;
+}
+
+int dlsym_many(void **dlp, const char *filename, ...)
+{
+       va_list ap;
+       void *dl;
+       int r;
+
+       if (*dlp)
+               return 0;
+
+       dl = dlopen(filename, RTLD_LAZY);
+       if (!dl)
+               return -ENOENT;
+
+       va_start(ap, filename);
+       r = dlsym_manyv(dl, ap);
+       va_end(ap);
+
+       if (r < 0) {
+               dlclose(dl);
+               return r;
+       }
+
+       *dlp = dl;
+
+       return 1;
+}
index 7c8bb95b4acbfcdac8f880c4c8b68af123d9f1bb..c6af2e3a361cd5db9fd674617a1037ef42595299 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <inttypes.h>
 #include <limits.h>
+#include <stdarg.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -165,3 +166,37 @@ static inline bool umulsz_overflow(size_t a, size_t b, size_t *res)
                (x) = NULL;        \
                x__;               \
        })
+
+/* dlfcn helpers                                                            */
+/* ************************************************************************ */
+
+/*
+ * Load many various symbols from @filename.
+ * @dlp: pointer to the previous results of this call: it's set when it succeeds
+ * @filename: the library to dlopen() and look for symbols
+ * @...: or 1 more tuples created by DLSYM_ARG() with ( &var, "symbol name" ).
+ */
+_sentinel_ int dlsym_many(void **dlp, const char *filename, ...);
+
+/*
+ * Helper to create tuples passed as arguments to dlsym_many().
+ * @symbol__: symbol to create arguments for. Example: DLSYM_ARG(foo) expands to
+ * `&sym_foo, "foo"`
+ */
+#define DLSYM_ARG(symbol__) &sym_##symbol__, STRINGIFY(symbol__),
+
+/* For symbols being dynamically loaded */
+#define DECLARE_DLSYM(symbol) typeof(symbol) *sym_##symbol = NULL
+
+/* Pointer indirection to support linking directly */
+#define DECLARE_PTRSYM(symbol) typeof(symbol) *sym_##symbol = symbol
+
+/*
+ * Helper defines, to be done locally before including this header to switch between
+ * implementations
+ */
+#if defined(DLSYM_LOCALLY_ENABLED) && DLSYM_LOCALLY_ENABLED
+#define DECLARE_SYM(sym__) DECLARE_DLSYM(sym__);
+#else
+#define DECLARE_SYM(sym__) DECLARE_PTRSYM(sym__);
+#endif