From 0b35be65b43f88f0a17a6f8830a52415c3ff1aa1 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 23 Jan 2017 09:36:20 +0200 Subject: Split code a bit, wrangle OpenGL Split system function hooks into hooks.h Wrangle opengl functions instead of trying to use them directly. --- hooks.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 hooks.h (limited to 'hooks.h') diff --git a/hooks.h b/hooks.h new file mode 100644 index 0000000..a96fcae --- /dev/null +++ b/hooks.h @@ -0,0 +1,172 @@ +#pragma once + +static void* (*_dlsym)(void*, const char*) = NULL; +static EGLBoolean (*_eglSwapBuffers)(EGLDisplay, EGLSurface) = NULL; +static __eglMustCastToProperFunctionPointerType (*_eglGetProcAddress)(const char*) = NULL; +static void (*_glXSwapBuffers)(Display*, GLXDrawable) = NULL; +static __GLXextFuncPtr (*_glXGetProcAddress)(const GLubyte*) = NULL; +static __GLXextFuncPtr (*_glXGetProcAddressARB)(const GLubyte*) = NULL; +static snd_pcm_sframes_t (*_snd_pcm_writei)(snd_pcm_t*, const void*, snd_pcm_uframes_t) = NULL; +static snd_pcm_sframes_t (*_snd_pcm_writen)(snd_pcm_t*, void**, snd_pcm_uframes_t) = NULL; +static snd_pcm_sframes_t (*_snd_pcm_mmap_writei)(snd_pcm_t*, const void*, snd_pcm_uframes_t) = NULL; +static snd_pcm_sframes_t (*_snd_pcm_mmap_writen)(snd_pcm_t*, void**, snd_pcm_uframes_t) = NULL; +static int (*_clock_gettime)(clockid_t, struct timespec*) = NULL; +static void* store_real_symbol_and_return_fake_symbol(const char*, void*); +static void hook_function(void**, const char*, const bool); + +#define HOOK(x) hook_function((void**)&_##x, #x, false) + +static uint64_t +get_time_ns(void) +{ + struct timespec ts; + HOOK(clock_gettime); + _clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * (uint64_t)1e9 + (uint64_t)ts.tv_nsec; +} + +EGLBoolean +eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + HOOK(eglSwapBuffers); + swap_buffers(); + return _eglSwapBuffers(dpy, surface); +} + +__eglMustCastToProperFunctionPointerType +eglGetProcAddress(const char *procname) +{ + HOOK(eglGetProcAddress); + return (_eglGetProcAddress ? store_real_symbol_and_return_fake_symbol(procname, _eglGetProcAddress(procname)) : NULL); +} + +void +glXSwapBuffers(Display *dpy, GLXDrawable drawable) +{ + HOOK(glXSwapBuffers); + swap_buffers(); + _glXSwapBuffers(dpy, drawable); +} + +__GLXextFuncPtr +glXGetProcAddressARB(const GLubyte *procname) +{ + HOOK(glXGetProcAddressARB); + return (_glXGetProcAddressARB ? store_real_symbol_and_return_fake_symbol((const char*)procname, _glXGetProcAddressARB(procname)) : NULL); +} + +__GLXextFuncPtr +glXGetProcAddress(const GLubyte *procname) +{ + HOOK(glXGetProcAddress); + return (_glXGetProcAddress ? store_real_symbol_and_return_fake_symbol((const char*)procname, _glXGetProcAddress(procname)) : NULL); +} + +snd_pcm_sframes_t +snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + HOOK(snd_pcm_writei); + alsa_writei(pcm, buffer, size, __func__); + return _snd_pcm_writei(pcm, buffer, size); +} + +snd_pcm_sframes_t +snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + HOOK(snd_pcm_writen); + // FIXME: Implement + return _snd_pcm_writen(pcm, bufs, size); +} + +snd_pcm_sframes_t +snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + HOOK(snd_pcm_mmap_writei); + alsa_writei(pcm, buffer, size, __func__); + return _snd_pcm_mmap_writei(pcm, buffer, size); +} + +snd_pcm_sframes_t +snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + HOOK(snd_pcm_mmap_writen); + // FIXME: Implement + return _snd_pcm_mmap_writen(pcm, bufs, size); +} + +int +clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + HOOK(clock_gettime); + + if ((clk_id == CLOCK_MONOTONIC || clk_id == CLOCK_MONOTONIC_RAW)) { + static __thread uint64_t base; + const uint64_t current = get_time_ns(); + if (!base) base = current; + const uint64_t fake = base + (current - base) * SPEED_HACK; + tp->tv_sec = fake / (uint64_t)1e9; + tp->tv_nsec = (fake % (uint64_t)1e9); + return 0; + } + + return _clock_gettime(clk_id, tp); +} + +#define HOOK_DLSYM(x) hook_function((void**)&_##x, #x, true) + +void* +dlsym(void *handle, const char *symbol) +{ + HOOK_DLSYM(dlsym); + + if (!strcmp(symbol, "dlsym")) + return dlsym; + + return store_real_symbol_and_return_fake_symbol(symbol, _dlsym(handle, symbol)); +} + +static void* +store_real_symbol_and_return_fake_symbol(const char *symbol, void *ret) +{ + if (!ret || !symbol) + return ret; + + if (0) {} +#define SET_IF_NOT_HOOKED(x, y) do { if (!_##x) { _##x = y; WARNX("SET %s to %p", #x, y); } } while (0) +#define FAKE_SYMBOL(x) else if (!strcmp(symbol, #x)) { SET_IF_NOT_HOOKED(x, ret); return x; } + FAKE_SYMBOL(eglSwapBuffers) + FAKE_SYMBOL(eglGetProcAddress) + FAKE_SYMBOL(glXSwapBuffers) + FAKE_SYMBOL(glXGetProcAddressARB) + FAKE_SYMBOL(glXGetProcAddress) + FAKE_SYMBOL(snd_pcm_writei) + FAKE_SYMBOL(snd_pcm_writen) + FAKE_SYMBOL(snd_pcm_mmap_writei) + FAKE_SYMBOL(snd_pcm_mmap_writen) + FAKE_SYMBOL(clock_gettime) +#undef FAKE_SYMBOL +#undef SET_IF_NOT_HOOKED + + return ret; +} + +static void +hook_function(void **ptr, const char *name, const bool versioned) +{ + if (*ptr) + return; + + if (versioned) { + const char *versions[] = { "GLIBC_2.0", "GLIBC_2.2.5", NULL }; + for (size_t i = 0; !*ptr && versions[i]; ++i) + *ptr = dlvsym(RTLD_NEXT, name, versions[i]); + } else { + HOOK_DLSYM(dlsym); + *ptr = _dlsym(RTLD_NEXT, name); + } + + if (!*ptr) + ERRX(EXIT_FAILURE, "HOOK FAIL %s", name); + + WARNX("HOOK %s", name); +} -- cgit v1.2.3