/* $Id$
This file is part of gldbg
-Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the GPL
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <dlfcn.h>
-#include <sys/uio.h>
-#include <GL/gl.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "arraysize.h"
+#include "breakpoint.h"
#include "functions.h"
+#include "opengl.h"
+#include "packet.h"
-static inline void *glsym(const char *sym)
+#define UNUSED __attribute__((unused))
+
+static unsigned char breakpoints[N_FUNCS] = { };
+static char break_any = 0;
+static char hold = 0;
+static char no_break = 0;
+
+static const char *get_lib_names(void)
+{
+ const char *env = getenv("GLWRAP_LIBS");
+ if(env)
+ return env;
+ return "libGL.so.1";
+}
+
+void *glsym(const char *name)
{
- static void *libgl = NULL;
- if(!libgl)
+ static void **gl_libs = NULL;
+ unsigned i;
+
+ if(!gl_libs)
{
- libgl = dlopen("libGL.so", RTLD_NOW);
- if(!libgl)
+ char *lib_names = strdup(get_lib_names());
+ unsigned n_libs = 1;
+ unsigned j;
+
+ for(i=0; lib_names[i]; ++i)
+ if(lib_names[i]==':')
+ ++n_libs;
+
+ gl_libs = (void **)malloc((n_libs+1)*sizeof(void *));
+ i = 0;
+ n_libs = 0;
+ for(j=0;; ++j)
{
- fprintf(stderr, "Could not open libGL: %s\n", dlerror());
- abort();
+ if(lib_names[j]==':' || lib_names[j]==0)
+ {
+ int at_end = (lib_names[j]==0);
+ lib_names[j] = 0;
+
+ gl_libs[n_libs] = dlopen(lib_names+i, RTLD_NOW);
+ if(!gl_libs[n_libs])
+ {
+ fprintf(stderr, "Could not open %s: %s\n", lib_names+i, dlerror());
+ abort();
+ }
+
+ i = j+1;
+ ++n_libs;
+
+ if(at_end)
+ break;
+ }
}
- }
- return dlsym(libgl, sym);
-}
-
-static char *buffer = 0;
-static char *write_pos;
-static struct iovec *iovecs = 0;
-static struct iovec *cur_vec;
-static unsigned length;
+ gl_libs[n_libs] = 0;
+ free(lib_names);
+ }
-static inline void next_vec()
-{
- if(write_pos!=cur_vec->iov_base)
+ for(i=0; gl_libs[i]; ++i)
{
- cur_vec->iov_len = write_pos-(char *)cur_vec->iov_base;
- length += cur_vec->iov_len;
- ++cur_vec;
- cur_vec->iov_base = write_pos;
+ void *sym = dlsym(gl_libs[i], name);
+ if(sym)
+ return sym;
}
-}
-
-static inline void write_bytes(const char *ptr, unsigned size)
-{
- unsigned i;
- for(i=0; i<size; ++i)
- *write_pos++ = *ptr++;
-}
-static inline void write_char(char v)
-{
- *write_pos++ = v;
+ return NULL;
}
-static inline void write_short(short v)
+int get_out_fd(void)
{
- write_bytes((char *)&v, sizeof(short));
-}
+ static int fd = -1;
-static inline void write_int(int v)
-{
- write_bytes((char *)&v, sizeof(int));
-}
+ if(fd<0)
+ {
+ const char *var = getenv("GLWRAP_FD");
+ if(var)
+ fd = strtol(var, NULL, 0);
+ else
+ {
+ var = getenv("GLWRAP_FILE");
+ if(var)
+ {
+ fd = open(var, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if(fd==-1)
+ {
+ fprintf(stderr, "Couldn't open dumpfile %s for output: %s", var, strerror(errno));
+ abort();
+ }
+ }
+ else
+ fd = 2;
+ }
+ }
-static inline void write_long(long v)
-{
- write_bytes((char *)&v, sizeof(long));
+ return fd;
}
-static inline void write_ulong(unsigned long v)
+int get_in_fd(void)
{
- write_bytes((char *)&v, sizeof(unsigned long));
-}
+ static int fd = -1;
-static inline void write_longlong(long long v)
-{
- write_bytes((char *)&v, sizeof(long long));
-}
+ if(fd<0)
+ {
+ const char *var = getenv("GLWRAP_CTRL_FD");
+ if(var)
+ fd = strtol(var, NULL, 0);
+ else
+ fd = 0;
+ }
-static inline void write_float(float v)
-{
- write_bytes((char *)&v, sizeof(float));
+ return fd;
}
-static inline void write_double(double v)
+static void receive_gldBreak(GlPacket *pkt)
{
- write_bytes((char *)&v, sizeof(double));
-}
+ unsigned short func;
+ unsigned char flags_set;
+ unsigned char flags_clr;
-static inline void write_pointer(const void *p)
-{
- write_bytes((char *)&p, sizeof(void *));
-}
+ packet_read_short(pkt, (short *)&func);
+ packet_read_char(pkt, (char *)&flags_set);
+ packet_read_char(pkt, (char *)&flags_clr);
-static inline void write_data(const void *data, unsigned size)
-{
- if(data)
+ if(func)
{
- write_int(size);
- next_vec();
- cur_vec->iov_base = (void *)data;
- cur_vec->iov_len = size;
- length += size;
- ++cur_vec;
- cur_vec->iov_base = write_pos;
+ breakpoints[func] &= ~flags_clr;
+ breakpoints[func] |= flags_set;
}
else
- write_int(0);
+ break_any = flags_set;
}
-static inline void write_string(const unsigned char *s)
+static void receive_gldHold(GlPacket *pkt UNUSED)
{
- write_data(s, strlen(s)+1);
+ hold = 1;
}
-static inline void begin_packet(int func)
+static void receive_gldQueryViewport(GlPacket *pkt UNUSED)
{
- if(!buffer)
- buffer = (char *)malloc(1024);
- if(!iovecs)
- iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
- write_pos = buffer;
- cur_vec = iovecs;
- cur_vec->iov_base = write_pos;
- length = 0;
- write_int(0);
- write_short(func);
-}
+ int viewport[4];
-static inline void send_packet()
-{
- static int fd = -1;
- if(fd<0)
- {
- const char *var = getenv("GLWRAP_FD");
- if(var)
- fd = strtol(var, NULL, 0);
- else
- fd = 2;
- }
- next_vec();
- write_pos = buffer;
- write_int(length);
- writev(fd, iovecs, cur_vec-iovecs);
+ no_break = 1;
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ no_break = 0;
}
-static inline int typesize(GLenum type)
+static void receive_gldReadPixels(GlPacket *pkt)
{
- switch(type)
- {
- case GL_BYTE: return sizeof(GLbyte);
- case GL_SHORT: return sizeof(GLshort);
- case GL_INT: return sizeof(GLint);
- case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
- case GL_UNSIGNED_SHORT: return sizeof(GLushort);
- case GL_UNSIGNED_INT: return sizeof(GLuint);
- case GL_FLOAT: return sizeof(GLfloat);
- case GL_DOUBLE: return sizeof(GLdouble);
- // Short and byte packed types are broken
- default: return 1;
- }
-}
+ GLint x, y;
+ GLsizei width, height;
+ GLenum format, type;
+ char *data;
-static inline int formatsize(GLenum format)
-{
- switch(format)
- {
- case GL_COLOR_INDEX: return 1;
- case GL_STENCIL_INDEX: return 1;
- case GL_DEPTH_COMPONENT: return 1;
- case GL_RED: return 1;
- case GL_GREEN: return 1;
- case GL_BLUE: return 1;
- case GL_ALPHA: return 1;
- case GL_RGB: return 3;
- case GL_RGBA: return 4;
- case GL_BGR: return 3;
- case GL_BGRA: return 4;
- case GL_LUMINANCE: return 1;
- case GL_LUMINANCE_ALPHA: return 2;
- default: return 1;
- }
+ packet_read_int(pkt, &x);
+ packet_read_int(pkt, &y);
+ packet_read_int(pkt, &width);
+ packet_read_int(pkt, &height);
+ packet_read_int(pkt, (int *)&format);
+ packet_read_int(pkt, (int *)&type);
+
+ data = (char *)malloc(width*height*typesize(type)*formatsize(format));
+ no_break = 1;
+ glReadPixels(x, y, width, height, format, type, data);
+ no_break = 0;
+ free(data);
}
-static inline int paramsize(GLenum pname)
+static void receive(void)
{
- switch(pname)
+ GlPacket *pkt;
+
+ while((pkt = packet_receive(get_in_fd())))
{
- // Lighting and material
- case GL_AMBIENT: return 4;
- case GL_DIFFUSE: return 4;
- case GL_AMBIENT_AND_DIFFUSE: return 4;
- case GL_SPECULAR: return 4;
- case GL_EMISSION: return 4;
- case GL_SHININESS: return 1;
- case GL_COLOR_INDEXES: return 3;
- case GL_POSITION: return 4;
- case GL_SPOT_DIRECTION: return 3;
- case GL_SPOT_EXPONENT: return 1;
- case GL_SPOT_CUTOFF: return 1;
- case GL_CONSTANT_ATTENUATION: return 1;
- case GL_LINEAR_ATTENUATION: return 1;
- case GL_QUADRATIC_ATTENUATION: return 1;
- case GL_LIGHT_MODEL_AMBIENT: return 4;
- case GL_LIGHT_MODEL_LOCAL_VIEWER: return 1;
- case GL_LIGHT_MODEL_TWO_SIDE: return 1;
- case GL_LIGHT_MODEL_COLOR_CONTROL: return 1;
-
- // Texture
- case GL_TEXTURE_WRAP_S: return 1;
- case GL_TEXTURE_WRAP_T: return 1;
- case GL_TEXTURE_WRAP_R: return 1;
- case GL_TEXTURE_MIN_FILTER: return 1;
- case GL_TEXTURE_MAG_FILTER: return 1;
- case GL_TEXTURE_BORDER_COLOR: return 4;
- case GL_TEXTURE_MIN_LOD: return 1;
- case GL_TEXTURE_MAX_LOD: return 1;
- case GL_TEXTURE_BASE_LEVEL: return 1;
- case GL_TEXTURE_MAX_LEVEL: return 1;
- case GL_TEXTURE_LOD_BIAS: return 1;
- case GL_DEPTH_TEXTURE_MODE: return 1;
- case GL_TEXTURE_COMPARE_MODE: return 1;
- case GL_TEXTURE_COMPARE_FUNC: return 1;
- case GL_GENERATE_MIPMAP: return 1;
- default: return 1;
+ unsigned short func;
+
+ packet_read_short(pkt, (short *)&func);
+ switch(func)
+ {
+ case FUNC_GLDBREAK: receive_gldBreak(pkt); break;
+ case FUNC_GLDHOLD: receive_gldHold(pkt); break;
+ case FUNC_GLDQUERYVIEWPORT: receive_gldQueryViewport(pkt); break;
+ case FUNC_GLDREADPIXELS: receive_gldReadPixels(pkt); break;
+ default:;
+ }
}
}
-static inline int mapsize(GLenum target)
+void tracepoint(unsigned short func, int flag)
{
- return 1;
-}
+ int breakpoint;
-void (*glXGetProcAddress(const GLubyte *procname))(void)
-{
- void *handle = dlopen(NULL, RTLD_LAZY);
- return dlsym(handle, (const char *)procname);
-}
+ if(no_break)
+ return;
-void (*glXGetProcAddressARB(const GLubyte *))(void) __attribute__((alias("glXGetProcAddress")));
+ receive();
-#include "glwrap.funcs"
+ breakpoint = (breakpoints[func]|break_any)&flag;
+ if(breakpoint || hold)
+ {
+ GlPacket *pkt;
+
+ if(breakpoint)
+ {
+ pkt = packet_begin(FUNC_GLDBREAK);
+ packet_write_short(pkt, func);
+ packet_write_char(pkt, flag);
+ packet_send(pkt, get_out_fd());
+ }
+
+ break_any = 0;
+
+ while(1)
+ {
+ hold = 0;
+ raise(SIGTRAP);
+ receive();
+ if(!hold)
+ break;
+ }
+ }
+}