_get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
-# Listing loaded libraries on other systems will try to use
-# functions common to Linux and a few other Unix-like systems.
-# See the following for several platforms' documentation of the same API:
-# https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html
-# https://man.freebsd.org/cgi/man.cgi?query=dl_iterate_phdr
-# https://man.openbsd.org/dl_iterate_phdr
-# https://docs.oracle.com/cd/E88353_01/html/E37843/dl-iterate-phdr-3c.html
-if (os.name == "posix" and
- sys.platform not in {"darwin", "ios", "tvos", "watchos"}):
- import ctypes
- if hasattr((_libc := ctypes.CDLL(None)), "dl_iterate_phdr"):
-
- class _dl_phdr_info(ctypes.Structure):
- _fields_ = [
- ("dlpi_addr", ctypes.c_void_p),
- ("dlpi_name", ctypes.c_char_p),
- ("dlpi_phdr", ctypes.c_void_p),
- ("dlpi_phnum", ctypes.c_ushort),
- ]
-
- _dl_phdr_callback = ctypes.CFUNCTYPE(
- ctypes.c_int,
- ctypes.POINTER(_dl_phdr_info),
- ctypes.c_size_t,
- ctypes.POINTER(ctypes.py_object),
- )
-
- @_dl_phdr_callback
- def _info_callback(info, _size, data):
- libraries = data.contents.value
- name = os.fsdecode(info.contents.dlpi_name)
- libraries.append(name)
- return 0
-
- _dl_iterate_phdr = _libc["dl_iterate_phdr"]
- _dl_iterate_phdr.argtypes = [
- _dl_phdr_callback,
- ctypes.POINTER(ctypes.py_object),
- ]
- _dl_iterate_phdr.restype = ctypes.c_int
-
- def dllist():
- """Return a list of loaded shared libraries in the current process."""
- libraries = []
- _dl_iterate_phdr(_info_callback,
- ctypes.byref(ctypes.py_object(libraries)))
- return libraries
+# On platforms which provide dl_iterate_phdr(), dllist() is implemented
+# in _ctypes.
+try:
+ from _ctypes import dllist
+except ImportError:
+ pass
@dataclass(slots=True, frozen=True)
--- /dev/null
+:func:`ctypes.util.dllist` now works on NetBSD. It is implemented in the
+:mod:`!_ctypes` extension module so that ``dl_iterate_phdr()`` reports all
+loaded shared libraries: on NetBSD it only reports the link-map group of
+the calling object, which excluded them when called through ctypes.
PyErr_Format(PyExc_OSError, "symbol '%s' not found", name);
return NULL;
}
+
+// Apple platforms use the dyld API in ctypes.util instead.
+#if defined(HAVE_DL_ITERATE_PHDR) && !defined(__APPLE__)
+#include <link.h>
+
+static int
+_dllist_callback(struct dl_phdr_info *info, size_t size, void *data)
+{
+ PyObject *list = (PyObject *)data;
+ PyObject *name = PyUnicode_DecodeFSDefault(info->dlpi_name);
+ if (name == NULL) {
+ return -1;
+ }
+ int res = PyList_Append(list, name);
+ Py_DECREF(name);
+ return res;
+}
+
+static PyObject *
+dllist(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ // On NetBSD dl_iterate_phdr() only reports the link-map group of the
+ // caller, so it cannot be called via a libffi trampoline.
+ PyObject *list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+ // The return value only echoes the callback result.
+ dl_iterate_phdr(_dllist_callback, list);
+ if (PyErr_Occurred()) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ return list;
+}
+#endif
#endif
/*
"dlopen(name, flag={RTLD_GLOBAL|RTLD_LOCAL}) open a shared library"},
{"dlclose", py_dl_close, METH_VARARGS, "dlclose a library"},
{"dlsym", py_dl_sym, METH_VARARGS, "find symbol in shared library"},
+#if defined(HAVE_DL_ITERATE_PHDR) && !defined(__APPLE__)
+ {"dllist", dllist, METH_NOARGS,
+ "dllist() return a list of loaded shared libraries"},
+#endif
#endif
#ifdef __APPLE__
{"_dyld_shared_cache_contains_path", py_dyld_shared_cache_contains_path, METH_VARARGS, "check if path is in the shared cache"},
fi
+# Used by ctypes.util.dllist().
+ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
+if test "x$ac_cv_func_dl_iterate_phdr" = xyes
+then :
+ printf "%s\n" "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h
+
+fi
+
+
# DYNLOADFILE specifies which dynload_*.o file we will use for dynamic
# loading of modules.
# platforms have dlopen(), but don't want to use it.
AC_CHECK_FUNCS([dlopen])
+# Used by ctypes.util.dllist().
+AC_CHECK_FUNCS([dl_iterate_phdr])
+
# DYNLOADFILE specifies which dynload_*.o file we will use for dynamic
# loading of modules.
AC_SUBST([DYNLOADFILE])
/* Define to 1 if you have the 'dlopen' function. */
#undef HAVE_DLOPEN
+/* Define to 1 if you have the 'dl_iterate_phdr' function. */
+#undef HAVE_DL_ITERATE_PHDR
+
/* Define to 1 if you have the 'dup' function. */
#undef HAVE_DUP