From bb3aba9080632fd2286ae30616ae414c0b862ce5 Mon Sep 17 00:00:00 2001 From: jackun Date: Mon, 16 Mar 2020 22:35:34 +0200 Subject: [PATCH] [OpenGL] Use elfhacks to load real OpenGL functions --- src/gl/inject.cpp | 8 +--- src/gl/real_dlsym.cpp | 83 ++++++++++++++++++++++++++++++++++----- src/gl/real_dlsym.h | 20 +--------- src/loaders/loader_gl.cpp | 11 ++++-- src/loaders/loader_gl.h | 2 +- src/meson.build | 1 + 6 files changed, 86 insertions(+), 39 deletions(-) diff --git a/src/gl/inject.cpp b/src/gl/inject.cpp index a97832e..e415b43 100644 --- a/src/gl/inject.cpp +++ b/src/gl/inject.cpp @@ -186,10 +186,10 @@ void* get_proc_address(const char* name) { void* get_glx_proc_address(const char* name) { if (!gl.Load()) { // Force load libGL then. If it still doesn't find it, get_proc_address should quit the program - void *handle = dlopen("libGL.so.1", RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND); + void *handle = real_dlopen("libGL.so.1", RTLD_LAZY); if (!handle) std::cerr << "MANGOHUD: couldn't find libGL.so.1" << std::endl; - gl.Load(); + gl.Load(handle); } void *func = nullptr; @@ -332,8 +332,6 @@ static void *find_ptr(const char *name) } EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) { - gl.Load(); - //std::cerr << __func__ << ":" << procName << std::endl; void* func = find_ptr( (const char*)procName ); @@ -344,8 +342,6 @@ EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) { } EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) { - gl.Load(); - //std::cerr << __func__ << ":" << procName << std::endl; void* func = find_ptr( (const char*)procName ); diff --git a/src/gl/real_dlsym.cpp b/src/gl/real_dlsym.cpp index f570a1d..0c31427 100644 --- a/src/gl/real_dlsym.cpp +++ b/src/gl/real_dlsym.cpp @@ -1,18 +1,83 @@ -#include "real_dlsym.h" +/** + * \author Pyry Haulos + * \date 2007-2008 + * For conditions of distribution and use, see copyright notice in elfhacks.h + */ +#include #include -#include +#include "real_dlsym.h" +#include "elfhacks.h" -extern "C" void* __libc_dlsym( void* handle, const char* name ); +void *(*__dlopen)(const char *, int) = nullptr; +void *(*__dlsym)(void *, const char *) = nullptr; +static bool print_dlopen = getenv("MANGOHUD_DEBUG_DLOPEN") != nullptr; +static bool print_dlsym = getenv("MANGOHUD_DEBUG_DLSYM") != nullptr; -void* real_dlsym( void* handle, const char* name ) +void get_real_functions() { - static void *(*the_real_dlsym)( void*, const char* ); + eh_obj_t libdl; - if (!the_real_dlsym) { - void* libdl = dlopen( "libdl.so", RTLD_NOW | RTLD_LOCAL ); - the_real_dlsym = reinterpret_cast (__libc_dlsym( libdl, "dlsym" )); + if (eh_find_obj(&libdl, "*libdl.so*")) { + fprintf(stderr, "can't get libdl.so\n"); + exit(1); } - return the_real_dlsym( handle, name ); + if (eh_find_sym(&libdl, "dlopen", (void **) &__dlopen)) { + fprintf(stderr, "can't get dlopen()\n"); + exit(1); + } + + if (eh_find_sym(&libdl, "dlsym", (void **) &__dlsym)) { + fprintf(stderr, "can't get dlsym()\n"); + exit(1); + } + + eh_destroy_obj(&libdl); +} + +/** + * \brief dlopen() wrapper, just passes calls to real dlopen() + * and writes information to standard output + */ +void *real_dlopen(const char *filename, int flag) +{ + if (__dlopen == nullptr) + get_real_functions(); + + void *result = __dlopen(filename, flag); + + if (print_dlopen) { + printf("dlopen(%s, ", filename); + const char *fmt = "%s"; + #define FLAG(test) if (flag & test) { printf(fmt, #test); fmt = "|%s"; } + FLAG(RTLD_LAZY) + FLAG(RTLD_NOW) + FLAG(RTLD_GLOBAL) + FLAG(RTLD_LOCAL) + FLAG(RTLD_NODELETE) + FLAG(RTLD_NOLOAD) + FLAG(RTLD_DEEPBIND) + #undef FLAG + printf(") = %p\n", result); + } + + return result; +} + +/** + * \brief dlsym() wrapper, passes calls to real dlsym() and + * writes information to standard output + */ +void *real_dlsym(void *handle, const char *symbol) +{ + if (__dlsym == nullptr) + get_real_functions(); + + void *result = __dlsym(handle, symbol); + + if (print_dlsym) + printf("dlsym(%p, %s) = %p\n", handle, symbol, result); + + return result; } diff --git a/src/gl/real_dlsym.h b/src/gl/real_dlsym.h index e9ba258..603007c 100644 --- a/src/gl/real_dlsym.h +++ b/src/gl/real_dlsym.h @@ -1,22 +1,4 @@ -/* -Copyright (C) 2016-2017 Björn Spindel - -This file is part of libstrangle. - -libstrangle is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -libstrangle is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with libstrangle. If not, see . -*/ - #pragma once +void *real_dlopen(const char *filename, int flag); void* real_dlsym( void*, const char* ); diff --git a/src/loaders/loader_gl.cpp b/src/loaders/loader_gl.cpp index 292ea06..d8c8802 100644 --- a/src/loaders/loader_gl.cpp +++ b/src/loaders/loader_gl.cpp @@ -8,14 +8,17 @@ gl_loader::~gl_loader() { CleanUp(loaded_); } -bool gl_loader::Load(bool egl_only) { +bool gl_loader::Load(void *handle, bool egl_only) { if (loaded_) { return true; } + if (!handle) + handle = RTLD_NEXT; + eglSwapBuffers = reinterpret_casteglSwapBuffers)>( - real_dlsym(RTLD_NEXT, "eglSwapBuffers")); + real_dlsym(handle, "eglSwapBuffers")); if (egl_only) { loaded_ = true; @@ -24,11 +27,11 @@ bool gl_loader::Load(bool egl_only) { glXGetProcAddress = reinterpret_castglXGetProcAddress)>( - real_dlsym(RTLD_NEXT, "glXGetProcAddress")); + real_dlsym(handle, "glXGetProcAddress")); glXGetProcAddressARB = reinterpret_castglXGetProcAddressARB)>( - real_dlsym(RTLD_NEXT, "glXGetProcAddressARB")); + real_dlsym(handle, "glXGetProcAddressARB")); if (!glXGetProcAddress) { CleanUp(true); diff --git a/src/loaders/loader_gl.h b/src/loaders/loader_gl.h index 3dee24a..4823d96 100644 --- a/src/loaders/loader_gl.h +++ b/src/loaders/loader_gl.h @@ -9,7 +9,7 @@ class gl_loader { gl_loader(); ~gl_loader(); - bool Load(bool egl_only = false); + bool Load(void *handle = nullptr, bool egl_only = false); bool IsLoaded() { return loaded_; } decltype(&::glXGetProcAddress) glXGetProcAddress; diff --git a/src/meson.build b/src/meson.build index cb91803..157a7dc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -51,6 +51,7 @@ vklayer_files = files( 'iostats.cpp', 'gpu.cpp', 'notify.cpp', + 'elfhacks.cpp', ) opengl_files = files(