import ctypes import ctypes.util import sys # dlfcn.h _RTLD_DI_LINKMAP = 2 class _LinkMap(ctypes.Structure): # pylint: disable=too-few-public-methods # link.h _fields_ = [ ('l_addr', ctypes.c_void_p), ('l_name', ctypes.c_char_p), ('l_ld', ctypes.c_void_p), ('l_next', ctypes.c_void_p), ('l_previous', ctypes.c_void_p), ] _LIBDL = ctypes.cdll.LoadLibrary(ctypes.util.find_library('dl')) _DLINFO = _LIBDL.dlinfo _DLINFO.argtypes = ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p _DLINFO.restype = ctypes.c_int class DLInfo: # pylint: disable=too-few-public-methods """ >>> lib = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c')) >>> dlinfo = DLInfo(lib) >>> dlinfo.path '/lib/x86_64-linux-gnu/libc.so.6' """ def __init__(self, cdll: ctypes.CDLL): _linkmap = ctypes.c_void_p() # pylint: disable=protected-access if _DLINFO(cdll._handle, _RTLD_DI_LINKMAP, ctypes.byref(_linkmap)) != 0: # pragma: no cover raise Exception(f"dlinfo on {cdll._name} failed") self._linkmap = ctypes.cast(_linkmap, ctypes.POINTER(_LinkMap)) @property def path(self) -> str: return self._linkmap.contents.l_name.decode(sys.getdefaultencoding())