+#ifdef __GNUC__
+#define unused __attribute__ ((unused))
+#else
+#define unused
+#endif
+
+void **wrapper_handles;
+int num_wrapper_handles;
+
+/* FIXME: Both count_chars and open_wrapper_handles are copied code
+ * from glaze-gl.c. It would be better to avoid this code
+ * duplication. */
+
+/* Count the number of types 'chr' appears in 'str' */
+static int
+count_chars (const char *str, char chr)
+{
+ int count = 0;
+ const char *s = str;
+
+ while (1) {
+ s = strchr (s, chr);
+ if (s == NULL)
+ break;
+ count++;
+ s++;
+ if (*s == '\0')
+ break;
+ }
+
+ return count;
+}
+
+static void
+open_wrapper_handles (void)
+{
+ const char *path;
+ char *path_copy, *wrapper, *save;
+ int i;
+
+ if (wrapper_handles)
+ return;
+
+ path = getenv ("GLAZE_WRAPPER");
+ if (path == NULL) {
+ fprintf (stderr, "GLAZE_WRAPPER unset. Please set to path of Glaze-using wrapper library.\n");
+ exit (1);
+ }
+
+ num_wrapper_handles = count_chars (path, ':') + 1;
+
+ wrapper_handles = malloc (num_wrapper_handles * sizeof (void*));
+ if (wrapper_handles == NULL) {
+ fprintf (stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ /* Clear dlerror state. */
+ dlerror ();
+
+ path_copy = strdup (path);
+ if (path_copy == NULL) {
+ fprintf (stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ for (i = 0, wrapper = strtok_r (path_copy, ":", &save);
+ i < num_wrapper_handles;
+ i++, wrapper = strtok_r (NULL, ":", &save))
+ {
+ wrapper_handles[i] = dlopen (wrapper, RTLD_LAZY);
+ if (wrapper_handles[i] == NULL) {
+ const char *error = dlerror();
+ fprintf (stderr, "Error: Failed to dlopen %s: %s\n",
+ wrapper, error);
+ exit (1);
+ }
+ }
+
+ free (path_copy);
+}
+
+static int
+symbol_is_in_backtrace (void *symbol, void **bt, int num_bt)
+{
+ Dl_info info;
+ int status;
+ int i;
+
+ for (i = 0; i < num_bt; i++) {
+ status = dladdr (bt[i], &info);
+ if (status == 0)
+ continue;
+ if (info.dli_saddr == symbol)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* FIXME: The hardcoded MAX_BT value here is uncool.
+ *
+ * If the number is too small, we could miss one of the wrapper
+ * functions in the backtrace which could lead to an infinite
+ * loop. For this bound, something on the order of the number of
+ * wrappers is likely sufficiently large.
+ *
+ * Meanwhile, if the number here is too large, we just waste a bunch
+ * of time grubbing through the backtrace of the application itself.
+ *
+ * The Right Thing to do here is to look at the back trace and ensure
+ * we have seen back to Glaze's libGL.so. If we see that, then we've
+ * looked far enough and should not have to look any further.
+ *
+ * Until then, 15 levels of backtrace out to be enough for anybody...
+ */
+#define MAX_BT 15
+