From 4556c734700da2dd95d4f148d6929a537882bade Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 23 Jan 2014 13:12:26 -0800 Subject: [PATCH] loader: Use dlsym to get our udev symbols instead of explicit linking. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steam links against libudev.so.0, while we're linking against libudev.so.1. The result is that the symbol names (which are the same in the two libraries) end up conflicting, and some of the usage of .so.1 calls the .so.0 bits, which have different internal structures, and segfaults happen. By using a dlopen() with RTLD_LOCAL, we can explicitly look for the symbols we want, while they get the symbols they want. Reviewed-by: Keith Packard Reviewed-by: Kristian Høgsberg Tested-by: Alexandre Demers Tested-by: Mike Lothian --- configure.ac | 2 +- src/egl/main/Makefile.am | 2 +- src/loader/Makefile.am | 5 +---- src/loader/loader.c | 42 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 33ac9225948..d266d96b674 100644 --- a/configure.ac +++ b/configure.ac @@ -858,7 +858,7 @@ xyesno) if test x"$enable_dri3$have_libudev" = xyesyes; then X11_INCLUDES="$X11_INCLUDES $LIBUDEV_CFLAGS" - GL_LIB_DEPS="$GL_LIB_DEPS $LIBUDEV_LIBS" + GL_LIB_DEPS="$GL_LIB_DEPS" fi # need DRM libs, $PTHREAD_LIBS, etc. diff --git a/src/egl/main/Makefile.am b/src/egl/main/Makefile.am index 60cb6006b50..e12aeae59b9 100644 --- a/src/egl/main/Makefile.am +++ b/src/egl/main/Makefile.am @@ -112,7 +112,7 @@ if HAVE_EGL_DRIVER_DRI2 AM_CFLAGS += -D_EGL_BUILT_IN_DRIVER_DRI2 AM_CFLAGS += -DHAVE_XCB_DRI2 libEGL_la_LIBADD += ../drivers/dri2/libegl_dri2.la -libEGL_la_LIBADD += $(LIBUDEV_LIBS) $(DLOPEN_LIBS) $(LIBDRM_LIBS) +libEGL_la_LIBADD += $(DLOPEN_LIBS) $(LIBDRM_LIBS) endif # Provide compatibility with scripts for the old Mesa build system for diff --git a/src/loader/Makefile.am b/src/loader/Makefile.am index 371dd575c09..bddf7ac35ed 100644 --- a/src/loader/Makefile.am +++ b/src/loader/Makefile.am @@ -29,9 +29,6 @@ libloader_la_CPPFLAGS = \ $(VISIBILITY_CFLAGS) \ $(LIBUDEV_CFLAGS) -libloader_la_LIBADD = \ - $(LIBUDEV_LIBS) - if !HAVE_LIBDRM libloader_la_CPPFLAGS += \ -D__NOT_HAVE_DRM_H @@ -39,7 +36,7 @@ else libloader_la_CPPFLAGS += \ $(LIBDRM_CFLAGS) -libloader_la_LIBADD += \ +libloader_la_LIBADD = \ $(LIBDRM_LIBS) endif diff --git a/src/loader/loader.c b/src/loader/loader.c index a5bd7692e6e..63b977aa743 100644 --- a/src/loader/loader.c +++ b/src/loader/loader.c @@ -67,6 +67,8 @@ #include #include #include +#include +#include #include "loader.h" #ifndef __NOT_HAVE_DRM_H @@ -92,11 +94,37 @@ static void (*log_)(int level, const char *fmt, ...) = default_logger; #ifdef HAVE_LIBUDEV #include +static void *udev_handle = NULL; + +static void * +udev_dlopen_handle(void) +{ + if (!udev_handle) { + udev_handle = dlopen("libudev.so.1", RTLD_LOCAL | RTLD_LAZY); + } + + return udev_handle; +} + +static void * +asserted_dlsym(void *dlopen_handle, const char *name) +{ + void *result = dlsym(dlopen_handle, name); + assert(result); + return result; +} + +#define UDEV_SYMBOL(ret, name, args) \ + ret (*name) args = asserted_dlsym(udev_dlopen_handle(), #name); + + static inline struct udev_device * udev_device_new_from_fd(struct udev *udev, int fd) { struct udev_device *device; struct stat buf; + UDEV_SYMBOL(struct udev_device *, udev_device_new_from_devnum, + (struct udev *udev, char type, dev_t devnum)); if (fstat(fd, &buf) < 0) { log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d", fd); @@ -119,6 +147,14 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) struct udev *udev = NULL; struct udev_device *device = NULL, *parent; const char *pci_id; + UDEV_SYMBOL(struct udev *, udev_new, (void)); + UDEV_SYMBOL(struct udev_device *, udev_device_get_parent, + (struct udev_device *)); + UDEV_SYMBOL(const char *, udev_device_get_property_value, + (struct udev_device *, const char *)); + UDEV_SYMBOL(struct udev_device *, udev_device_unref, + (struct udev_device *)); + UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *)); *chip_id = -1; @@ -240,6 +276,12 @@ loader_get_device_name_for_fd(int fd) struct udev *udev; struct udev_device *device; const char *const_device_name; + UDEV_SYMBOL(struct udev *, udev_new, (void)); + UDEV_SYMBOL(const char *, udev_device_get_devnode, + (struct udev_device *)); + UDEV_SYMBOL(struct udev_device *, udev_device_unref, + (struct udev_device *)); + UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *)); udev = udev_new(); device = udev_device_new_from_fd(udev, fd);