source/glprint.c \
source/enums.c \
source/arraysize.c \
- source/tmpalloc.c
+ source/tmpalloc.c \
+ source/packet.c
SOURCES_glwrap := source/glwrap.c \
source/glwrap_funcs.c \
- source/arraysize.c
+ source/arraysize.c \
+ source/packet.c \
+ source/tmpalloc.c
SOURCES_gldump := source/gldump.c
SOURCES_gldbg := source/gldbg.cpp \
source/commandinterpreter.cpp \
$(OBJECTS_gldbg): CXXFLAGS += $(shell pkg-config --cflags $(PACKAGES_gldbg))
gldbg: LIBS += $(shell pkg-config --libs $(PACKAGES_gldbg)) -lreadline
gldump gldbg: LIBS += ./libgldbg.a
+glwrap.so: LDFLAGS += -s
-glwrap.so: $(OBJECTS_glwrap)
+glwrap.so: $(OBJECTS_glwrap) glwrap.ld
$(CC) -shared -o $@ $^ $(LIBS) $(LDFLAGS)
gldump: $(OBJECTS_gldump) libgldbg.a
#include "functions.h"
#include "glwrap.h"
#include "opengl.h"
+#include "packet.h"
-int in_begin_block = 0;
-GLenum cur_error = GL_NO_ERROR;
+static int in_begin_block = 0;
+static GLenum cur_error = GL_NO_ERROR;
static void check_error()
{
- GLenum (*orig_glGetError)() = 0;
+ static GLenum (*orig_glGetError)() = NULL;
GLenum code;
if(in_begin_block)
code = orig_glGetError();
if(code!=GL_NO_ERROR)
{
- begin_packet(FUNC_GLDERROR);
- write_int(code);
- send_packet();
+ GlPacket *pkt;
+
+ pkt = packet_begin(FUNC_GLDERROR);
+ packet_write_int(pkt, code);
+ packet_send(pkt, get_out_fd());
if(cur_error==GL_NO_ERROR)
cur_error = code;
void APIENTRY glBegin(GLenum mode)
{
- static void (*orig)(GLenum);
+ static void (*orig)(GLenum) = NULL;
+ GlPacket *pkt;
+
if(!orig)
orig = glsym("glBegin");
orig(mode);
- begin_packet(FUNC_GLBEGIN);
- write_int(mode);
- send_packet();
+ pkt = packet_begin(FUNC_GLBEGIN);
+ packet_write_int(pkt, mode);
+ packet_send(pkt, get_out_fd());
in_begin_block = 1;
}
void APIENTRY glEnd()
{
- static void (*orig)();
+ static void (*orig)() = NULL;
+ GlPacket *pkt;
+
if(!orig)
orig = glsym("glEnd");
orig();
- begin_packet(FUNC_GLEND);
- send_packet();
+ pkt = packet_begin(FUNC_GLEND);
+ packet_send(pkt, get_out_fd());
in_begin_block = 0;
check_error();
GLenum APIENTRY glGetError()
{
GLenum ret = GL_NO_ERROR;
+ GlPacket *pkt;
if(in_begin_block)
{
cur_error = GL_NO_ERROR;
}
- begin_packet(FUNC_GLGETERROR);
- write_int(ret);
- send_packet();
+ pkt = packet_begin(FUNC_GLGETERROR);
+ packet_write_int(pkt, ret);
+ packet_send(pkt, get_out_fd());
return ret;
}
{
void *handle = 0;
void (*ret)() = 0;
+ GlPacket *pkt;
if(glsym((const char *)procname))
{
ret = dlsym(handle, (const char *)procname);
}
- begin_packet(FUNC_GLXGETPROCADDRESS);
- write_string((const char *)procname);
- write_pointer(ret);
- send_packet();
+ pkt = packet_begin(FUNC_GLXGETPROCADDRESS);
+ packet_write_string(pkt, (const char *)procname);
+ packet_write_pointer(pkt, ret);
+ packet_send(pkt, get_out_fd());
return ret;
}
#include "functions.h"
#include "glwrap.h"
#include "opengl.h"
+#include "packet.h"
GLenum cur_error = GL_NO_ERROR;
static void check_error()
{
- GLenum (*orig_glGetError)() = 0;
+ GLenum (*orig_glGetError)() = NULL;
GLenum code;
if(!orig_glGetError)
code = orig_glGetError();
if(code!=GL_NO_ERROR)
{
- begin_packet(FUNC_GLDERROR);
- write_int(code);
- send_packet();
+ GlPacket *pkt;
+
+ pkt = packet_begin(FUNC_GLDERROR);
+ packet_write_int(pkt, code);
+ packet_send(pkt, get_out_fd());
if(cur_error==GL_NO_ERROR)
cur_error = code;
{
GLenum ret = cur_error;
cur_error = GL_NO_ERROR;
+ GlPacket *pkt;
- begin_packet(FUNC_GLGETERROR);
- write_int(ret);
- send_packet();
+ pkt = packet_begin(FUNC_GLGETERROR);
+ packet_write_int(pkt, ret);
+ packet_send(pkt, get_out_fd());
return ret;
}
void (*eglGetProcAddress(const char *procname))(void)
{
- void *handle = 0;
- void (*ret)() = 0;
+ void *handle = NULL;
+ void (*ret)() = NULL;
+ GlPacket *pkt;
if(glsym((const char *)procname))
{
ret = dlsym(handle, (const char *)procname);
}
- begin_packet(FUNC_EGLGETPROCADDRESS);
- write_pointer(ret);
- write_string((const char *)procname);
- send_packet();
+ pkt = packet_begin(FUNC_EGLGETPROCADDRESS);
+ packet_write_pointer(pkt, ret);
+ packet_write_string(pkt, (const char *)procname);
+ packet_send(pkt, get_out_fd());
return ret;
}
--- /dev/null
+/* $Id$ */
+
+VERSION
+{
+ {
+ global:
+ gl*;
+ local:
+ *;
+ };
+}
/* $Id$
This file is part of gldbg
-Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions
Distributed under the GPL
*/
#include <string.h>
#include "functions.h"
#include "gldecoder.h"
-#include "tmpalloc.h"
+#include "packet.h"
-typedef struct sGlPacket
-{
- const char *ptr;
- unsigned chunk;
- unsigned total;
-} GlPacket;
-
-static void read_short(short *, GlPacket *);
-static void read_int(int *, GlPacket *);
static int decode_func(GlDecoder *, unsigned short, GlPacket *);
static int decode_gldfunc(GlDecoder *, unsigned short, GlPacket *);
int gldecoder_decode(GlDecoder *dec, const char *data, unsigned len)
{
+ GlPacket *pkt;
unsigned short func;
- GlPacket packet;
-
- if(len<sizeof(int)+sizeof(short))
- return -1;
-
- packet.ptr = data;
- packet.chunk = len;
- read_int((int *)&packet.chunk, &packet);
-
- if(packet.chunk&0x80000000)
- {
- packet.chunk &= 0x7FFFFFFF;
- packet.total = packet.chunk;
-
- while(1)
- {
- if(len<packet.total+sizeof(int))
- return -1;
-
- GlPacket p = { packet.ptr+packet.total, len-packet.total, 0 };
- unsigned chunk;
- read_int((int *)&chunk, &p);
- packet.total += chunk&0x7FFFFFFF;
- if(!(chunk&0x80000000))
- break;
- }
- }
- else
- packet.total = packet.chunk;
- if(len<packet.total)
+ pkt = packet_receive_str(data, &len);
+ if(!pkt)
return -1;
- read_short((short *)&func, &packet);
+ packet_read_short(pkt, (short *)&func);
if(dec)
{
int ret = 0;
if(func&0x8000)
- ret = decode_gldfunc(dec, func, &packet);
+ ret = decode_gldfunc(dec, func, pkt);
else
- ret = decode_func(dec, func, &packet);
+ ret = decode_func(dec, func, pkt);
if(ret<0)
return -1;
}
- return packet.ptr+packet.total-data;
-}
-
-static void next_chunk(GlPacket *pkt)
-{
- if(pkt->total==0)
- return;
- pkt->chunk = pkt->total;
- read_int((int *)&pkt->chunk, pkt);
- pkt->chunk &= 0x7FFFFFFF;
-}
-
-static void read_generic(void *v, unsigned size, int byteswap, GlPacket *pkt)
-{
- if(pkt->chunk==0)
- next_chunk(pkt);
-
- if(pkt->chunk>=size)
- {
- // TODO: Actually implement byteswap if needed
- (void)byteswap;
- memcpy(v, pkt->ptr, size);
- pkt->ptr += size;
- pkt->chunk -= size;
- pkt->total -= size;
- }
- else
- {
- memset(v, 0, size);
- pkt->total -= pkt->chunk;
- pkt->chunk = 0;
- }
-}
-
-static void read_char(char *v, GlPacket *pkt)
-{
- read_generic(v, 1, 0, pkt);
-}
-
-static void read_short(short *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(short), 1, pkt);
-}
-
-static void read_int(int *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(int), 1, pkt);
-}
-
-static void read_long(long *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(long), 1, pkt);
-}
-
-static void read_long_long(long long *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(long long), 1, pkt);
-}
-
-static void read_float(float *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(float), 1, pkt);
-}
-
-static void read_double(double *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(double), 1, pkt);
-}
-
-typedef const void *pointer;
-
-static void read_pointer(pointer *v, GlPacket *pkt)
-{
- read_generic(v, sizeof(pointer), 1, pkt);
-}
-
-static void read_data(pointer *v, GlPacket *pkt)
-{
- int vlen;
- read_int(&vlen, pkt);
- if(vlen)
- *v = pkt->ptr;
- else
- *v = NULL;
- pkt->ptr += vlen;
- pkt->chunk -= vlen;
- pkt->total -= vlen;
-}
-
-typedef const char *string;
-
-static void read_string(string *v, GlPacket *pkt)
-{
- read_data((pointer *)v, pkt);
-}
-
-static void read_string_array(string **v, GlPacket *pkt)
-{
- int count;
- int i;
- read_int(&count, pkt);
- *v = (string *)tmpalloc(count*sizeof(string));
- for(i=0; i<count; ++i)
- read_string(*v+i, pkt);
+ return len;
}
#include "gensrc/gldecoder.funcs"
static void decode_gldError(GlDecoder *dec, GlPacket *pkt)
{
GLenum code;
- read_int((int *)&code, pkt);
+ packet_read_int(pkt, (int *)&code);
if(dec->gldError)
dec->gldError(dec->user_data, code);
}
wl(' %s p_%s;', p.ctype, p.name)
for p in params:
if p.kind=="value":
- wl(' read_%s((%s *)&p_%s, pkt);', p.io[0].replace(' ', '_'), p.io[0], p.name)
+ wl(' packet_read_%s(pkt, (%s *)&p_%s);', p.io[0].replace(' ', '_'), p.io[0], p.name)
elif p.kind=="array" and p.io and p.io[0]=="string":
- wl(' read_string_array(&p_%s, pkt);', p.name)
+ wl(' packet_read_string_array(pkt, &p_%s);', p.name)
elif p.csize:
- wl(' read_data((pointer *)&p_%s, pkt);', p.name)
+ wl(' packet_read_data(pkt, (pointer *)&p_%s);', p.name)
else:
- wl(' read_pointer((pointer *)&p_%s, pkt);', p.name)
+ wl(' packet_read_pointer(pkt, (pointer *)&p_%s);', p.name)
if ret.ctype!="void":
- wl(' read_%s((%s *)&ret, pkt);', ret.io[0].replace(' ', '_'), ret.io[0])
+ wl(' packet_read_%s(pkt, (%s *)&ret);', ret.io[0].replace(' ', '_'), ret.io[0])
wl(' if(dec->%s)', func.name)
w(' dec->%s(dec->user_data', func.name)
if ret.ctype!="void":
#include <errno.h>
#include <dlfcn.h>
#include <fcntl.h>
-#include <sys/uio.h>
-#define INTERNAL __attribute__((visibility("internal")))
-
-INTERNAL inline const char *get_lib_names(void)
+static const char *get_lib_names(void)
{
const char *env = getenv("GLWRAP_LIBS");
if(env)
return env;
- return "libGL.so";
+ return "libGL.so.1";
}
-INTERNAL inline void *glsym(const char *name)
+void *glsym(const char *name)
{
static void **gl_libs = NULL;
unsigned i;
return NULL;
}
-INTERNAL char *buffer = 0;
-INTERNAL char *write_pos;
-INTERNAL struct iovec *iovecs = 0;
-INTERNAL struct iovec *cur_vec;
-INTERNAL unsigned length;
-
-INTERNAL inline void next_vec(void)
-{
- if(write_pos!=cur_vec->iov_base)
- {
- cur_vec->iov_len = write_pos-(char *)cur_vec->iov_base;
- length += cur_vec->iov_len;
- ++cur_vec;
- cur_vec->iov_base = write_pos;
- }
-}
-
-INTERNAL inline void write_bytes(const char *ptr, unsigned size)
-{
- unsigned i;
- for(i=0; i<size; ++i)
- *write_pos++ = *ptr++;
-}
-
-INTERNAL inline void write_char(char v)
-{
- *write_pos++ = v;
-}
-
-INTERNAL inline void write_short(short v)
-{
- write_bytes((char *)&v, sizeof(short));
-}
-
-INTERNAL inline void write_int(int v)
-{
- write_bytes((char *)&v, sizeof(int));
-}
-
-INTERNAL inline void write_long(long v)
-{
- write_bytes((char *)&v, sizeof(long));
-}
-
-INTERNAL inline void write_long_long(long long v)
-{
- write_bytes((char *)&v, sizeof(long long));
-}
-
-INTERNAL inline void write_float(float v)
-{
- write_bytes((char *)&v, sizeof(float));
-}
-
-INTERNAL inline void write_double(double v)
-{
- write_bytes((char *)&v, sizeof(double));
-}
-
-INTERNAL inline void write_pointer(const void *p)
-{
- write_bytes((char *)&p, sizeof(void *));
-}
-
-INTERNAL inline void write_data(const void *data, unsigned size)
-{
- if(data)
- {
- 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;
- }
- else
- write_int(0);
-}
-
-INTERNAL inline void write_string(const char *s)
-{
- write_data(s, strlen(s)+1);
-}
-
-INTERNAL inline void write_string_array(const char **sa, unsigned size)
-{
- unsigned i;
- size /= sizeof(const char *);
- write_int(size);
- for(i=0; i<size; ++i)
- write_string(sa[i]);
-}
-
-INTERNAL inline void begin_packet(int func)
-{
- 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);
-}
-
-INTERNAL inline int get_out_fd(void)
+int get_out_fd(void)
{
static int fd = -1;
var = getenv("GLWRAP_FILE");
if(var)
{
- fd = open(var, O_WRONLY|O_CREAT, 0644);
+ 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));
return fd;
}
-
-INTERNAL inline void send_partial_packet(void)
-{
- next_vec();
- write_pos = buffer;
- write_int(length|0x80000000);
- writev(get_out_fd(), iovecs, cur_vec-iovecs);
-
- write_pos = buffer;
- cur_vec = iovecs;
- cur_vec->iov_base = write_pos;
- length = 0;
-
- write_int(0);
-}
-
-INTERNAL inline void send_packet(void)
-{
- next_vec();
- write_pos = buffer;
- write_int(length);
- writev(get_out_fd(), iovecs, cur_vec-iovecs);
-}
!handcode eglGetProcAddress
wl('%s APIENTRY %s(%s)', ret.ctype, func.name, ", ".join([p.ctype+" "+p.name for p in params]))
wl('{')
-wl(' static %s (*orig)(%s);', ret.ctype, ", ".join([p.ctype for p in params]))
+wl(' static %s (*orig)(%s) = NULL;', ret.ctype, ", ".join([p.ctype for p in params]))
+wl(' GlPacket *pkt;')
if ret.ctype!='void':
wl(' %s ret;', ret.ctype)
wl(' if(!orig)')
wl(' orig = glsym("%s");', func.name)
-wl(' begin_packet(FUNC_%s);', func.name.upper())
+wl(' pkt = packet_begin(FUNC_%s);', func.name.upper())
head_sent = False
for p in params:
if p.direction=="out" and not head_sent:
- wl(' send_partial_packet();')
+ wl(' packet_send_partial(pkt, get_out_fd());')
w(' ')
if ret.ctype!='void':
w('ret = ')
wl('orig(%s);', ", ".join([q.name for q in params]))
head_sent = True
if p.kind=="value":
- wl(' write_%s(%s);', p.io[0].replace(' ', '_'), p.name)
+ wl(' packet_write_%s(pkt, %s);', p.io[0].replace(' ', '_'), p.name)
elif p.kind=="array" and p.io and p.io[0]=="string":
- wl(' write_string_array(%s, %s);', p.name, p.csize)
+ wl(' packet_write_string_array(pkt, %s, %s);', p.name, p.csize)
elif p.csize:
- wl(' write_data(%s, %s);', p.name, p.csize)
+ wl(' packet_write_data(pkt, %s, %s);', p.name, p.csize)
else:
- wl(' write_pointer(%s);', p.name)
+ wl(' packet_write_pointer(pkt, %s);', p.name)
if ret.ctype!='void':
if not head_sent:
- wl(' send_partial_packet();')
+ wl(' packet_send_partial(pkt, get_out_fd());')
wl(' ret = orig(%s);', ", ".join([p.name for p in params]))
head_sent = True
- wl(' write_%s(ret);', ret.io[0].replace(' ', '_'))
-wl(' send_packet();')
+ wl(' packet_write_%s(pkt, ret);', ret.io[0].replace(' ', '_'))
+wl(' packet_send(pkt, get_out_fd());')
if not head_sent:
wl(' orig(%s);', ", ".join([p.name for p in params]))
if not func.name.startswith("glX"):
wl(' check_error();')
+#wl(' receive_packet();')
if ret.ctype!='void':
wl(' return ret;')
wl('}')
#define GLWRAP_H_
void *glsym(const char *);
-void write_char(char);
-void write_short(short);
-void write_int(int);
-void write_long(long);
-void write_long_long(long long);
-void write_float(float);
-void write_double(double);
-void write_pointer(const void *);
-void write_data(const void *, unsigned);
-void write_string(const char *);
-void write_string_array(const char **, unsigned);
-void begin_packet(int);
-void send_partial_packet(void);
-void send_packet(void);
+int get_out_fd(void);
#endif
--- /dev/null
+/* $Id$
+
+This file is part of gldbg
+Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include "packet.h"
+#include "tmpalloc.h"
+
+struct GlOutPacket
+{
+ char *ptr;
+ unsigned length;
+ struct iovec *vec;
+};
+
+struct GlInPacket
+{
+ const char *ptr;
+ unsigned length;
+ unsigned chunk;
+};
+
+typedef struct GlOutPacket GlOutPacket;
+typedef struct GlInPacket GlInPacket;
+
+struct GlPacket
+{
+ union
+ {
+ GlOutPacket out;
+ GlInPacket in;
+ };
+};
+
+// XXX Should make this stuff truly re-entrant
+static char *out_buffer = 0;
+static struct iovec *iovecs = 0;
+static GlPacket packet;
+/*static char *in_buffer = 0;
+static unsigned in_length;*/
+
+static void next_vec(GlPacket *pkt)
+{
+ GlOutPacket *out = &pkt->out;
+
+ if(out->ptr!=out->vec->iov_base)
+ {
+ out->vec->iov_len = out->ptr-(char *)out->vec->iov_base;
+ out->length += out->vec->iov_len;
+ ++out->vec;
+ out->vec->iov_base = out->ptr;
+ }
+}
+
+static void reset(GlPacket *pkt)
+{
+ GlOutPacket *out = &pkt->out;
+
+ out->ptr = out_buffer;
+ out->vec = iovecs;
+ out->vec->iov_base = out->ptr;
+ out->length = 0;
+}
+
+GlPacket *packet_begin(unsigned short func)
+{
+ GlPacket *pkt;
+
+ if(!out_buffer)
+ out_buffer = (char *)malloc(1024);
+ if(!iovecs)
+ iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
+
+ pkt = &packet;
+ reset(pkt);
+
+ packet_write_int(pkt, 0);
+ packet_write_short(pkt, func);
+
+ return pkt;
+}
+
+void packet_send_partial(GlPacket *pkt, int fd)
+{
+ GlOutPacket *out = &pkt->out;
+
+ out->length |= 0x80000000;
+ packet_send(pkt, fd);
+
+ reset(pkt);
+
+ packet_write_int(pkt, 0);
+}
+
+void packet_send(GlPacket *pkt, int fd)
+{
+ GlOutPacket *out = &pkt->out;
+ struct iovec *v;
+
+ next_vec(pkt);
+ out->ptr = out_buffer;
+ packet_write_int(pkt, out->length);
+
+ for(v=iovecs; v!=out->vec; )
+ {
+ int ret;
+
+ ret = writev(fd, v, out->vec-v);
+ if(ret<0)
+ return;
+
+ while(v!=out->vec && (unsigned)ret>=v->iov_len)
+ {
+ ret -= v->iov_len;
+ ++v;
+ }
+
+ if(v!=out->vec)
+ {
+ v->iov_base += ret;
+ v->iov_len -= ret;
+ }
+ }
+}
+
+static void write_raw(GlPacket *pkt, const char *ptr, unsigned size, int byteswap)
+{
+ GlOutPacket *out = &pkt->out;
+ unsigned i;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if(byteswap)
+ {
+ ptr += size;
+ for(i=0; i<size; ++i)
+ *out->ptr++ = *--ptr;
+ }
+ else
+#endif
+ {
+ for(i=0; i<size; ++i)
+ *out->ptr++ = *ptr++;
+ }
+}
+
+void packet_write_char(GlPacket *pkt, char v)
+{
+ GlOutPacket *out = &pkt->out;
+ *out->ptr++ = v;
+}
+
+void packet_write_short(GlPacket *pkt, short v)
+{
+ write_raw(pkt, (char *)&v, sizeof(short), 1);
+}
+
+void packet_write_int(GlPacket *pkt, int v)
+{
+ write_raw(pkt, (char *)&v, sizeof(int), 1);
+}
+
+void packet_write_long(GlPacket *pkt, long v)
+{
+ write_raw(pkt, (char *)&v, sizeof(long), 1);
+}
+
+void packet_write_long_long(GlPacket *pkt, long long v)
+{
+ write_raw(pkt, (char *)&v, sizeof(long long), 1);
+}
+
+void packet_write_float(GlPacket *pkt, float v)
+{
+ write_raw(pkt, (char *)&v, sizeof(float), 1);
+}
+
+void packet_write_double(GlPacket *pkt, double v)
+{
+ write_raw(pkt, (char *)&v, sizeof(double), 1);
+}
+
+void packet_write_pointer(GlPacket *pkt, const void *p)
+{
+ write_raw(pkt, (char *)&p, sizeof(void *), 1);
+}
+
+void packet_write_data(GlPacket *pkt, const void *data, unsigned size)
+{
+ if(data)
+ {
+ GlOutPacket *out = &pkt->out;
+
+ packet_write_int(pkt, size);
+ next_vec(pkt);
+ out->vec->iov_base = (void *)data;
+ out->vec->iov_len = size;
+ out->length += size;
+ ++out->vec;
+ out->vec->iov_base = out->ptr;
+ }
+ else
+ packet_write_int(pkt, 0);
+}
+
+void packet_write_string(GlPacket *pkt, const char *s)
+{
+ packet_write_data(pkt, s, strlen(s)+1);
+}
+
+void packet_write_string_array(GlPacket *pkt, const char **sa, unsigned size)
+{
+ unsigned i;
+ size /= sizeof(const char *);
+ packet_write_int(pkt, size);
+ for(i=0; i<size; ++i)
+ packet_write_string(pkt, sa[i]);
+}
+
+GlPacket *packet_receive_str(const char *data, unsigned *len)
+{
+ const char *end = data+*len;
+ GlPacket *pkt;
+ GlInPacket *in;
+
+ if(*len<sizeof(int)+sizeof(short))
+ return 0;
+
+ pkt = &packet;
+ in = &pkt->in;
+ in->ptr = data;
+ in->chunk = *len;
+
+ packet_read_int(pkt, (int *)&in->chunk);
+
+ if(in->chunk&0x80000000)
+ {
+ in->chunk &= 0x7FFFFFFF;
+ in->length = in->chunk;
+
+ while(1)
+ {
+ if(end<in->ptr+in->length+sizeof(int))
+ return NULL;
+
+ GlPacket p;
+ p.in.ptr = in->ptr+in->length;
+ p.in.chunk = p.in.length = end-p.in.ptr;
+
+ unsigned chunk;
+ packet_read_int(&p, (int *)&chunk);
+
+ in->length += chunk&0x7FFFFFFF;
+ if(!(chunk&0x80000000))
+ break;
+ }
+ }
+ else
+ in->length = in->chunk;
+
+ if(end<in->ptr+in->length)
+ return NULL;
+
+ *len = in->ptr+in->length-data;
+
+ return pkt;
+}
+
+static void next_chunk(GlPacket *pkt)
+{
+ GlInPacket *in = &pkt->in;
+
+ if(in->length==0)
+ return;
+
+ in->chunk = in->length;
+ packet_read_int(pkt, (int *)&in->chunk);
+ in->chunk &= 0x7FFFFFFF;
+}
+
+static void read_raw(GlPacket *pkt, char *ptr, unsigned size, int byteswap)
+{
+ GlInPacket *in = &pkt->in;
+
+ if(in->chunk==0)
+ next_chunk(pkt);
+
+ if(in->chunk>=size)
+ {
+ unsigned i;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if(byteswap)
+ {
+ ptr += size;
+ for(i=0; i<size; ++i)
+ *--ptr = *in->ptr++;
+ }
+ else
+#endif
+ {
+ for(i=0; i<size; ++i)
+ *ptr++ = *in->ptr++;
+ }
+
+ in->length -= size;
+ in->chunk -= size;
+ }
+ else
+ {
+ memset(ptr, 0, size);
+ in->length -= in->chunk;
+ in->chunk = 0;
+ }
+}
+
+void packet_read_char(GlPacket *pkt, char *v)
+{
+ read_raw(pkt, v, 1, 0);
+}
+
+void packet_read_short(GlPacket *pkt, short *v)
+{
+ read_raw(pkt, (char *)v, sizeof(short), 1);
+}
+
+void packet_read_int(GlPacket *pkt, int *v)
+{
+ read_raw(pkt, (char *)v, sizeof(int), 1);
+}
+
+void packet_read_long(GlPacket *pkt, long *v)
+{
+ read_raw(pkt, (char *)v, sizeof(long), 1);
+}
+
+void packet_read_long_long(GlPacket *pkt, long long *v)
+{
+ read_raw(pkt, (char *)v, sizeof(long long), 1);
+}
+
+void packet_read_float(GlPacket *pkt, float *v)
+{
+ read_raw(pkt, (char *)v, sizeof(float), 1);
+}
+
+void packet_read_double(GlPacket *pkt, double *v)
+{
+ read_raw(pkt, (char *)v, sizeof(double), 1);
+}
+
+void packet_read_pointer(GlPacket *pkt, pointer *v)
+{
+ read_raw(pkt, (char *)v, sizeof(pointer), 1);
+}
+
+void packet_read_data(GlPacket *pkt, pointer *v)
+{
+ GlInPacket *in = &pkt->in;
+ int vlen;
+
+ packet_read_int(pkt, &vlen);
+ if(vlen)
+ *v = in->ptr;
+ else
+ *v = NULL;
+ in->ptr += vlen;
+ in->chunk -= vlen;
+ in->length -= vlen;
+}
+
+void packet_read_string(GlPacket *pkt, string *v)
+{
+ packet_read_data(pkt, (pointer *)v);
+}
+
+void packet_read_string_array(GlPacket *pkt, string **v)
+{
+ int count;
+ int i;
+ packet_read_int(pkt, &count);
+ *v = (string *)tmpalloc(count*sizeof(string));
+ for(i=0; i<count; ++i)
+ packet_read_string(pkt, *v+i);
+}
--- /dev/null
+/* $Id$
+
+This file is part of gldbg
+Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#ifndef PACKET_H_
+#define PACKET_H_
+
+struct GlPacket;
+typedef struct GlPacket GlPacket;
+
+GlPacket *packet_begin(unsigned short);
+void packet_send_partial(GlPacket *, int);
+void packet_send(GlPacket *, int);
+
+// XXX Should use something with fixed sizes
+
+void packet_write_char(GlPacket *, char);
+void packet_write_short(GlPacket *, short);
+void packet_write_int(GlPacket *, int);
+void packet_write_long(GlPacket *, long);
+void packet_write_long_long(GlPacket *, long long);
+void packet_write_float(GlPacket *, float);
+void packet_write_double(GlPacket *, double);
+void packet_write_pointer(GlPacket *, const void *);
+void packet_write_data(GlPacket *, const void *, unsigned);
+void packet_write_string(GlPacket *, const char *);
+void packet_write_string_array(GlPacket *, const char **, unsigned);
+
+GlPacket *packet_receive_str(const char *, unsigned *);
+
+void packet_read_char(GlPacket *, char *);
+void packet_read_short(GlPacket *, short *);
+void packet_read_int(GlPacket *, int *);
+void packet_read_long(GlPacket *, long *);
+void packet_read_long_long(GlPacket *, long long *);
+void packet_read_float(GlPacket *, float *);
+void packet_read_double(GlPacket *, double *);
+typedef const void *pointer;
+void packet_read_pointer(GlPacket *, pointer *);
+void packet_read_data(GlPacket *, pointer *);
+typedef const char *string;
+void packet_read_string(GlPacket *, string *);
+void packet_read_string_array(GlPacket *, string **);
+
+#endif