summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--glcapture.c277
-rw-r--r--glwrangle.h86
-rw-r--r--hooks.h172
3 files changed, 319 insertions, 216 deletions
diff --git a/glcapture.c b/glcapture.c
index 4ae6bad..2aefb69 100644
--- a/glcapture.c
+++ b/glcapture.c
@@ -15,7 +15,6 @@
*/
#define _GNU_SOURCE
-#define GL_GLEXT_PROTOTYPES
#include <dlfcn.h>
#include <GL/glx.h>
#include <EGL/egl.h>
@@ -98,33 +97,17 @@ struct fifo {
bool created;
};
-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 ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define WARN(x, ...) do { warn("glcapture: "x, ##__VA_ARGS__); } while (0)
#define WARNX(x, ...) do { warnx("glcapture: "x, ##__VA_ARGS__); } while (0)
#define ERRX(x, y, ...) do { errx(x, "glcapture: "y, ##__VA_ARGS__); } while (0)
#define WARN_ONCE(x, ...) do { static bool o = false; if (!o) { WARNX(x, ##__VA_ARGS__); o = true; } } while (0)
-#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;
-}
+static void swap_buffers(void);
+static void alsa_writei(snd_pcm_t *pcm, const void *buffer, const snd_pcm_uframes_t size, const char *caller);
+
+#include "hooks.h"
+#include "glwrangle.h"
static void
reset_fifo(struct fifo *fifo)
@@ -287,64 +270,6 @@ write_data(const struct frame_info *info, const void *buffer, const size_t size)
pthread_mutex_unlock(&mutex);
}
-static const char*
-alsa_get_format(const snd_pcm_format_t format)
-{
- switch (format) {
- case SND_PCM_FORMAT_FLOAT64_LE: return "f64le";
- case SND_PCM_FORMAT_FLOAT64_BE: return "f64be";
- case SND_PCM_FORMAT_FLOAT_LE: return "f32le";
- case SND_PCM_FORMAT_FLOAT_BE: return "f32be";
- case SND_PCM_FORMAT_S32_LE: return "s32le";
- case SND_PCM_FORMAT_S32_BE: return "s32be";
- case SND_PCM_FORMAT_U32_LE: return "u32le";
- case SND_PCM_FORMAT_U32_BE: return "u32be";
- case SND_PCM_FORMAT_S24_LE: return "s24le";
- case SND_PCM_FORMAT_S24_BE: return "s24be";
- case SND_PCM_FORMAT_U24_LE: return "u24le";
- case SND_PCM_FORMAT_U24_BE: return "u24be";
- case SND_PCM_FORMAT_S16_LE: return "s16le";
- case SND_PCM_FORMAT_S16_BE: return "s16be";
- case SND_PCM_FORMAT_U16_LE: return "u16le";
- case SND_PCM_FORMAT_U16_BE: return "u16be";
- case SND_PCM_FORMAT_S8: return "s8";
- case SND_PCM_FORMAT_U8: return "u8";
- case SND_PCM_FORMAT_MU_LAW: return "mulaw";
- case SND_PCM_FORMAT_A_LAW: return "alaw";
- default: break;
- }
-
- WARN_ONCE("can't convert alsa format: %u", format);
- return NULL;
-}
-
-static bool
-alsa_get_frame_info(snd_pcm_t *pcm, struct frame_info *out_info, const char *caller)
-{
- snd_pcm_format_t format;
- unsigned int channels, rate;
- snd_pcm_hw_params_t *params = alloca(snd_pcm_hw_params_sizeof());
- snd_pcm_hw_params_current(pcm, params);
- snd_pcm_hw_params_get_format(params, &format);
- snd_pcm_hw_params_get_channels(params, &channels);
- snd_pcm_hw_params_get_rate(params, &rate, NULL);
- WARN_ONCE("%s (%s:%u:%u)", caller, snd_pcm_format_name(format), rate, channels);
- out_info->ts = get_time_ns();
- out_info->stream = STREAM_AUDIO;
- out_info->audio.format = alsa_get_format(format);
- out_info->audio.rate = rate;
- out_info->audio.channels = channels;
- return (out_info->audio.format != NULL);
-}
-
-static void
-alsa_writei(snd_pcm_t *pcm, const void *buffer, const snd_pcm_uframes_t size, const char *caller)
-{
- struct frame_info info;
- if (alsa_get_frame_info(pcm, &info, caller))
- write_data(&info, buffer, snd_pcm_frames_to_bytes(pcm, size));
-}
-
static void
capture_frame_pbo(struct gl *gl, const GLint view[4], const uint64_t ts)
{
@@ -429,7 +354,7 @@ static void
draw_indicator(const GLint view[4])
{
const uint32_t size = (view[3] / 75 > 10 ? view[3] / 75 : 10);
- glPushAttrib(GL_ENABLE_BIT);
+ glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(size / 2 - 1, view[3] - size - size / 2 - 1, size + 2, size + 2);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -444,6 +369,14 @@ draw_indicator(const GLint view[4])
static void
swap_buffers(void)
{
+ void* (*procs[])(const char*) = {
+ (void*)_eglGetProcAddress,
+ (void*)_glXGetProcAddressARB,
+ (void*)_glXGetProcAddress
+ };
+
+ load_gl_function_pointers(procs, ARRAY_SIZE(procs));
+
GLint view[4] = {0};
static __thread struct gl gl;
const GLenum error0 = glGetError();
@@ -457,148 +390,60 @@ swap_buffers(void)
}
}
-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)
+static const char*
+alsa_get_format(const snd_pcm_format_t format)
{
- 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;
+ switch (format) {
+ case SND_PCM_FORMAT_FLOAT64_LE: return "f64le";
+ case SND_PCM_FORMAT_FLOAT64_BE: return "f64be";
+ case SND_PCM_FORMAT_FLOAT_LE: return "f32le";
+ case SND_PCM_FORMAT_FLOAT_BE: return "f32be";
+ case SND_PCM_FORMAT_S32_LE: return "s32le";
+ case SND_PCM_FORMAT_S32_BE: return "s32be";
+ case SND_PCM_FORMAT_U32_LE: return "u32le";
+ case SND_PCM_FORMAT_U32_BE: return "u32be";
+ case SND_PCM_FORMAT_S24_LE: return "s24le";
+ case SND_PCM_FORMAT_S24_BE: return "s24be";
+ case SND_PCM_FORMAT_U24_LE: return "u24le";
+ case SND_PCM_FORMAT_U24_BE: return "u24be";
+ case SND_PCM_FORMAT_S16_LE: return "s16le";
+ case SND_PCM_FORMAT_S16_BE: return "s16be";
+ case SND_PCM_FORMAT_U16_LE: return "u16le";
+ case SND_PCM_FORMAT_U16_BE: return "u16be";
+ case SND_PCM_FORMAT_S8: return "s8";
+ case SND_PCM_FORMAT_U8: return "u8";
+ case SND_PCM_FORMAT_MU_LAW: return "mulaw";
+ case SND_PCM_FORMAT_A_LAW: return "alaw";
+ default: break;
}
- 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));
+ WARN_ONCE("can't convert alsa format: %u", format);
+ return NULL;
}
-static void*
-store_real_symbol_and_return_fake_symbol(const char *symbol, void *ret)
+static bool
+alsa_get_frame_info(snd_pcm_t *pcm, struct frame_info *out_info, const char *caller)
{
- 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;
+ snd_pcm_format_t format;
+ unsigned int channels, rate;
+ snd_pcm_hw_params_t *params = alloca(snd_pcm_hw_params_sizeof());
+ snd_pcm_hw_params_current(pcm, params);
+ snd_pcm_hw_params_get_format(params, &format);
+ snd_pcm_hw_params_get_channels(params, &channels);
+ snd_pcm_hw_params_get_rate(params, &rate, NULL);
+ WARN_ONCE("%s (%s:%u:%u)", caller, snd_pcm_format_name(format), rate, channels);
+ out_info->ts = get_time_ns();
+ out_info->stream = STREAM_AUDIO;
+ out_info->audio.format = alsa_get_format(format);
+ out_info->audio.rate = rate;
+ out_info->audio.channels = channels;
+ return (out_info->audio.format != NULL);
}
static void
-hook_function(void **ptr, const char *name, const bool versioned)
+alsa_writei(snd_pcm_t *pcm, const void *buffer, const snd_pcm_uframes_t size, const char *caller)
{
- 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);
+ struct frame_info info;
+ if (alsa_get_frame_info(pcm, &info, caller))
+ write_data(&info, buffer, snd_pcm_frames_to_bytes(pcm, size));
}
diff --git a/glwrangle.h b/glwrangle.h
new file mode 100644
index 0000000..f6b2555
--- /dev/null
+++ b/glwrangle.h
@@ -0,0 +1,86 @@
+#pragma once
+
+static GLenum (*_glGetError)(void);
+static void (*_glGetIntegerv)(GLenum, GLint*);
+static GLboolean (*_glIsBuffer)(GLuint);
+static void (*_glGenBuffers)(GLsizei, GLuint*);
+static void (*_glDeleteBuffers)(GLsizei, GLuint*);
+static void (*_glBindBuffer)(GLenum, GLuint);
+static void (*_glBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
+static void* (*_glMapBuffer)(GLenum, GLenum);
+static void (*_glUnmapBuffer)(GLenum);
+static void (*_glPixelStorei)(GLenum, GLint);
+static void (*_glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*);
+static void (*_glPushClientAttrib)(GLbitfield);
+static void (*_glPopClientAttrib)(void);
+static void (*_glPushAttrib)(GLbitfield);
+static void (*_glPopAttrib)(void);
+static void (*_glEnable)(GLenum);
+static void (*_glDisable)(GLenum);
+static void (*_glScissor)(GLint, GLint, GLsizei, GLsizei);
+static void (*_glClearColor)(GLclampf, GLclampf, GLclampf, GLclampf);
+static void (*_glClear)(GLbitfield);
+
+#define glGetError _glGetError
+#define glGetIntegerv _glGetIntegerv
+#define glIsBuffer _glIsBuffer
+#define glGenBuffers _glGenBuffers
+#define glDeleteBuffers _glDeleteBuffers
+#define glBindBuffer _glBindBuffer
+#define glBufferData _glBufferData
+#define glMapBuffer _glMapBuffer
+#define glUnmapBuffer _glUnmapBuffer
+#define glPixelStorei _glPixelStorei
+#define glReadPixels _glReadPixels
+#define glPushClientAttrib _glPushClientAttrib
+#define glPopClientAttrib _glPopClientAttrib
+#define glPushAttrib _glPushAttrib
+#define glPopAttrib _glPopAttrib
+#define glEnable _glEnable
+#define glDisable _glDisable
+#define glScissor _glScissor
+#define glClearColor _glClearColor
+#define glClear _glClear
+
+static void
+load_gl_function_pointers(void* (*procs[])(const char*), const size_t memb)
+{
+ static bool loaded;
+
+ if (loaded)
+ return;
+
+ void* (*proc)(const char*);
+ for (size_t i = 0; i < memb; ++i) {
+ if ((proc = procs[i]))
+ break;
+ }
+
+ if (!proc)
+ ERRX(EXIT_FAILURE, "There is no proc loader available");
+
+#define GL(x) do { if (!(_##x = proc(#x))) { ERRX(EXIT_FAILURE, "Failed to load %s", #x); } } while (0)
+ GL(glGetError);
+ GL(glGetIntegerv);
+ GL(glIsBuffer);
+ GL(glGenBuffers);
+ GL(glDeleteBuffers);
+ GL(glBindBuffer);
+ GL(glBufferData);
+ GL(glMapBuffer);
+ GL(glUnmapBuffer);
+ GL(glPixelStorei);
+ GL(glReadPixels);
+ GL(glPushClientAttrib);
+ GL(glPopClientAttrib);
+ GL(glPushAttrib);
+ GL(glPopAttrib);
+ GL(glEnable);
+ GL(glDisable);
+ GL(glScissor);
+ GL(glClearColor);
+ GL(glClear);
+#undef GL
+
+ loaded = true;
+}
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);
+}