]> git.tdb.fi Git - gldbg.git/blob - source/glwrap.c
Send as much of a packet as possible before calling the original function
[gldbg.git] / source / glwrap.c
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2009-2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <dlfcn.h>
13 #include <fcntl.h>
14 #include <sys/uio.h>
15
16 #define INTERNAL __attribute__((visibility("internal")))
17
18 INTERNAL inline const char *get_lib_names(void)
19 {
20         const char *env = getenv("GLWRAP_LIBS");
21         if(env)
22                 return env;
23         return "libGL.so";
24 }
25
26 INTERNAL inline void *glsym(const char *name)
27 {
28         static void **gl_libs = NULL;
29         unsigned i;
30
31         if(!gl_libs)
32         {
33                 char *lib_names = strdup(get_lib_names());
34                 unsigned n_libs = 1;
35                 unsigned j;
36
37                 for(i=0; lib_names[i]; ++i)
38                         if(lib_names[i]==':')
39                                 ++n_libs;
40
41                 gl_libs = (void **)malloc((n_libs+1)*sizeof(void *));
42                 i = 0;
43                 n_libs = 0;
44                 for(j=0;; ++j)
45                 {
46                         if(lib_names[j]==':' || lib_names[j]==0)
47                         {
48                                 int at_end = (lib_names[j]==0);
49                                 lib_names[j] = 0;
50
51                                 gl_libs[n_libs] = dlopen(lib_names+i, RTLD_NOW);
52                                 if(!gl_libs[n_libs])
53                                 {
54                                         fprintf(stderr, "Could not open %s: %s\n", lib_names+i, dlerror());
55                                         abort();
56                                 }
57
58                                 i = j+1;
59                                 ++n_libs;
60
61                                 if(at_end)
62                                         break;
63                         }
64                 }
65
66                 gl_libs[n_libs] = 0;
67                 free(lib_names);
68         }
69
70         for(i=0; gl_libs[i]; ++i)
71         {
72                 void *sym = dlsym(gl_libs[i], name);
73                 if(sym)
74                         return sym;
75         }
76
77         return NULL;
78 }
79
80 INTERNAL char *buffer = 0;
81 INTERNAL char *write_pos;
82 INTERNAL struct iovec *iovecs = 0;
83 INTERNAL struct iovec *cur_vec;
84 INTERNAL unsigned length;
85
86 INTERNAL inline void next_vec(void)
87 {
88         if(write_pos!=cur_vec->iov_base)
89         {
90                 cur_vec->iov_len = write_pos-(char *)cur_vec->iov_base;
91                 length += cur_vec->iov_len;
92                 ++cur_vec;
93                 cur_vec->iov_base = write_pos;
94         }
95 }
96
97 INTERNAL inline void write_bytes(const char *ptr, unsigned size)
98 {
99         unsigned i;
100         for(i=0; i<size; ++i)
101                 *write_pos++ = *ptr++;
102 }
103
104 INTERNAL inline void write_char(char v)
105 {
106         *write_pos++ = v;
107 }
108
109 INTERNAL inline void write_short(short v)
110 {
111         write_bytes((char *)&v, sizeof(short));
112 }
113
114 INTERNAL inline void write_int(int v)
115 {
116         write_bytes((char *)&v, sizeof(int));
117 }
118
119 INTERNAL inline void write_long(long v)
120 {
121         write_bytes((char *)&v, sizeof(long));
122 }
123
124 INTERNAL inline void write_long_long(long long v)
125 {
126         write_bytes((char *)&v, sizeof(long long));
127 }
128
129 INTERNAL inline void write_float(float v)
130 {
131         write_bytes((char *)&v, sizeof(float));
132 }
133
134 INTERNAL inline void write_double(double v)
135 {
136         write_bytes((char *)&v, sizeof(double));
137 }
138
139 INTERNAL inline void write_pointer(const void *p)
140 {
141         write_bytes((char *)&p, sizeof(void *));
142 }
143
144 INTERNAL inline void write_data(const void *data, unsigned size)
145 {
146         if(data)
147         {
148                 write_int(size);
149                 next_vec();
150                 cur_vec->iov_base = (void *)data;
151                 cur_vec->iov_len = size;
152                 length += size;
153                 ++cur_vec;
154                 cur_vec->iov_base = write_pos;
155         }
156         else
157                 write_int(0);
158 }
159
160 INTERNAL inline void write_string(const char *s)
161 {
162         write_data(s, strlen(s)+1);
163 }
164
165 INTERNAL inline void write_string_array(const char **sa, unsigned size)
166 {
167         unsigned i;
168         size /= sizeof(const char *);
169         write_int(size);
170         for(i=0; i<size; ++i)
171                 write_string(sa[i]);
172 }
173
174 INTERNAL inline void begin_packet(int func)
175 {
176         if(!buffer)
177                 buffer = (char *)malloc(1024);
178         if(!iovecs)
179                 iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
180
181         write_pos = buffer;
182         cur_vec = iovecs;
183         cur_vec->iov_base = write_pos;
184         length = 0;
185
186         write_int(0);
187         write_short(func);
188 }
189
190 INTERNAL inline int get_out_fd(void)
191 {
192         static int fd = -1;
193
194         if(fd<0)
195         {
196                 const char *var = getenv("GLWRAP_FD");
197                 if(var)
198                         fd = strtol(var, NULL, 0);
199                 else
200                         fd = 2;
201         }
202
203         return fd;
204 }
205
206 INTERNAL inline void send_partial_packet(void)
207 {
208         next_vec();
209         write_pos = buffer;
210         write_int(length|0x80000000);
211         writev(get_out_fd(), iovecs, cur_vec-iovecs);
212
213         write_pos = buffer;
214         cur_vec = iovecs;
215         cur_vec->iov_base = write_pos;
216         length = 0;
217
218         write_int(0);
219 }
220
221 INTERNAL inline void send_packet(void)
222 {
223         next_vec();
224         write_pos = buffer;
225         write_int(length);
226         writev(get_out_fd(), iovecs, cur_vec-iovecs);
227 }