1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "ApiGen.h"
17 #include "EntryPoint.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include "strUtils.h"
21 #include <errno.h>
22 #include <sys/types.h>
23 
24 /* Define this to 1 to enable support for the 'isLarge' variable flag
25  * that instructs the encoder to send large data buffers by a direct
26  * write through the pipe (i.e. without copying it into a temporary
27  * buffer. This has definite performance benefits when using a QEMU Pipe.
28  *
29  * Set to 0 otherwise.
30  */
31 #define WITH_LARGE_SUPPORT  1
32 
findEntryByName(const std::string & name)33 EntryPoint * ApiGen::findEntryByName(const std::string & name)
34 {
35     EntryPoint * entry = NULL;
36 
37     size_t n = this->size();
38     for (size_t i = 0; i < n; i++) {
39         if (at(i).name() == name) {
40             entry = &(at(i));
41             break;
42         }
43     }
44     return entry;
45 }
46 
printHeader(FILE * fp) const47 void ApiGen::printHeader(FILE *fp) const
48 {
49     fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
50     fprintf(fp, "// generated by 'emugen'\n");
51 }
52 
genProcTypes(const std::string & filename,SideType side)53 int ApiGen::genProcTypes(const std::string &filename, SideType side)
54 {
55     FILE *fp = fopen(filename.c_str(), "wt");
56     if (fp == NULL) {
57         perror(filename.c_str());
58         return -1;
59     }
60     printHeader(fp);
61 
62     const char* basename = m_basename.c_str();
63 
64     fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side));
65     fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side));
66     fprintf(fp, "\n\n");
67     fprintf(fp, "\n#include \"%s_types.h\"\n",basename);
68     fprintf(fp, "#ifndef %s_APIENTRY\n",basename);
69     fprintf(fp, "#define %s_APIENTRY \n",basename);
70     fprintf(fp, "#endif\n");
71 
72 
73     for (size_t i = 0; i < size(); i++) {
74         EntryPoint *e = &at(i);
75 
76         fprintf(fp, "typedef ");
77         e->retval().printType(fp);
78         fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
79         if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
80         if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
81 
82         VarsArray & evars = e->vars();
83         size_t n = evars.size();
84 
85         for (size_t j = 0; j < n; j++) {
86             if (!evars[j].isVoid()) {
87                 if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
88                 evars[j].printType(fp);
89             }
90         }
91         fprintf(fp, ");\n");
92     }
93     fprintf(fp, "\n\n#endif\n");
94     return 0;
95 }
96 
genFuncTable(const std::string & filename,SideType side)97 int ApiGen::genFuncTable(const std::string &filename, SideType side)
98 {
99     FILE *fp = fopen(filename.c_str(), "wt");
100     if (fp == NULL) {
101         perror(filename.c_str());
102         return -1;
103     }
104     printHeader(fp);
105 
106     fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
107     fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
108     fprintf(fp, "\n\n");
109     fprintf(fp, "static struct _%s_funcs_by_name {\n", m_basename.c_str());
110     fprintf(fp,
111             "\tconst char *name;\n" \
112             "\tvoid *proc;\n" \
113             "} %s_funcs_by_name[] = {\n", m_basename.c_str());
114 
115 
116     for (size_t i = 0; i < size(); i++) {
117         EntryPoint *e = &at(i);
118         if (e->notApi()) continue;
119         fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str());
120     }
121     fprintf(fp, "};\n");
122     fprintf(fp, "static int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n",
123             m_basename.c_str(), m_basename.c_str(), m_basename.c_str());
124     fprintf(fp, "\n\n#endif\n");
125     return 0;
126 }
127 
128 
genContext(const std::string & filename,SideType side)129 int ApiGen::genContext(const std::string & filename, SideType side)
130 {
131     FILE *fp = fopen(filename.c_str(), "wt");
132     if (fp == NULL) {
133         perror(filename.c_str());
134         return -1;
135     }
136     printHeader(fp);
137 
138     fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
139     fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
140 
141     //  fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
142     fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", m_basename.c_str(), sideString(side));
143 
144     StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
145     for (size_t i = 0; i < contextHeaders.size(); i++) {
146         fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
147     }
148     fprintf(fp, "\n");
149 
150     fprintf(fp, "\nstruct %s_%s_context_t {\n\n", m_basename.c_str(), sideString(side));
151     for (size_t i = 0; i < size(); i++) {
152         EntryPoint *e = &at(i);
153         fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
154     }
155     // accessors
156     fprintf(fp, "\t//Accessors \n");
157 
158     for (size_t i = 0; i < size(); i++) {
159         EntryPoint *e = &at(i);
160         const char *n = e->name().c_str();
161         const char *s = sideString(side);
162         fprintf(fp, "\tvirtual %s_%s_proc_t set_%s(%s_%s_proc_t f) { %s_%s_proc_t retval = %s; %s = f; return retval;}\n", n, s, n, n, s, n, s,  n, n);
163     }
164 
165     // virtual destructor
166     fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
167     // accessor
168     if (side == CLIENT_SIDE || side == WRAPPER_SIDE) {
169         fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
170                 m_basename.c_str(), sideString(side));
171         fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
172     }
173 
174     // init function
175     fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
176 
177     //client site set error virtual func
178     if (side == CLIENT_SIDE) {
179         fprintf(fp, "\tvirtual void setError(unsigned int  error){};\n");
180         fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n");
181     }
182 
183     fprintf(fp, "};\n");
184 
185     fprintf(fp, "\n#endif\n");
186     fclose(fp);
187     return 0;
188 }
189 
genEntryPoints(const std::string & filename,SideType side)190 int ApiGen::genEntryPoints(const std::string & filename, SideType side)
191 {
192 
193     if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
194         fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
195         return -999;
196     }
197 
198 
199     FILE *fp = fopen(filename.c_str(), "wt");
200     if (fp == NULL) {
201         perror(filename.c_str());
202         return errno;
203     }
204 
205     printHeader(fp);
206     fprintf(fp, "#include <stdio.h>\n");
207     fprintf(fp, "#include <stdlib.h>\n");
208     fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side));
209     fprintf(fp, "\n");
210 
211     fprintf(fp, "#ifndef GL_TRUE\n");
212     fprintf(fp, "extern \"C\" {\n");
213 
214     for (size_t i = 0; i < size(); i++) {
215         fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
216     }
217     fprintf(fp, "};\n\n");
218     fprintf(fp, "#endif\n");
219 
220     fprintf(fp, "#ifndef GET_CONTEXT\n");
221     fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
222             m_basename.c_str(), sideString(side));
223 
224     fprintf(fp,
225             "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n",
226             m_basename.c_str(), sideString(side));
227     fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext() \n",
228                 m_basename.c_str(), sideString(side));
229     fprintf(fp, "#endif\n\n");
230 
231 
232     for (size_t i = 0; i < size(); i++) {
233         EntryPoint *e = &at(i);
234         e->print(fp);
235         fprintf(fp, "{\n");
236         fprintf(fp, "\tGET_CONTEXT; \n");
237 
238         bool shouldReturn = !e->retval().isVoid();
239         bool shouldCallWithContext = (side == CLIENT_SIDE);
240         //param check
241         if (shouldCallWithContext) {
242             for (size_t j=0; j<e->vars().size(); j++) {
243                 if (e->vars()[j].paramCheckExpression() != "")
244                     fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str());
245             }
246         }
247         fprintf(fp, "\t %sctx->%s(%s",
248                 shouldReturn ? "return " : "",
249                 e->name().c_str(),
250                 shouldCallWithContext ? "ctx" : "");
251         size_t nvars = e->vars().size();
252 
253         for (size_t j = 0; j < nvars; j++) {
254             if (!e->vars()[j].isVoid()) {
255                 fprintf(fp, "%s %s",
256                         j != 0 || shouldCallWithContext ? "," : "",
257                         e->vars()[j].name().c_str());
258             }
259         }
260         fprintf(fp, ");\n");
261         fprintf(fp, "}\n\n");
262     }
263     fclose(fp);
264     return 0;
265 }
266 
267 
genOpcodes(const std::string & filename)268 int ApiGen::genOpcodes(const std::string &filename)
269 {
270     FILE *fp = fopen(filename.c_str(), "wt");
271     if (fp == NULL) {
272         perror(filename.c_str());
273         return errno;
274     }
275 
276     printHeader(fp);
277     fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
278     fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
279     for (size_t i = 0; i < size(); i++) {
280         fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
281     }
282     fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
283     fprintf(fp,"\n\n#endif\n");
284     fclose(fp);
285     return 0;
286 
287 }
genAttributesTemplate(const std::string & filename)288 int ApiGen::genAttributesTemplate(const std::string &filename )
289 {
290     FILE *fp = fopen(filename.c_str(), "wt");
291     if (fp == NULL) {
292         perror(filename.c_str());
293         return -1;
294     }
295 
296     for (size_t i = 0; i < size(); i++) {
297         if (at(i).hasPointers()) {
298             fprintf(fp, "#");
299             at(i).print(fp);
300             fprintf(fp, "%s\n\n", at(i).name().c_str());
301         }
302     }
303     fclose(fp);
304     return 0;
305 }
306 
genEncoderHeader(const std::string & filename)307 int ApiGen::genEncoderHeader(const std::string &filename)
308 {
309     FILE *fp = fopen(filename.c_str(), "wt");
310     if (fp == NULL) {
311         perror(filename.c_str());
312         return -1;
313     }
314 
315     printHeader(fp);
316     std::string classname = m_basename + "_encoder_context_t";
317 
318     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
319     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
320 
321     fprintf(fp, "#include \"IOStream.h\"\n");
322     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
323 
324     for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
325         fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
326     }
327     fprintf(fp, "\n");
328 
329     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
330             classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
331     fprintf(fp, "\tIOStream *m_stream;\n\n");
332 
333     fprintf(fp, "\t%s(IOStream *stream);\n\n", classname.c_str());
334     fprintf(fp, "\n};\n\n");
335 
336     fprintf(fp,"extern \"C\" {\n");
337 
338     for (size_t i = 0; i < size(); i++) {
339         fprintf(fp, "\t");
340         at(i).print(fp, false, "_enc", /* classname + "::" */"", "void *self");
341         fprintf(fp, ";\n");
342     }
343     fprintf(fp, "};\n");
344     fprintf(fp, "#endif");
345 
346     fclose(fp);
347     return 0;
348 }
349 
350 // Format the byte length expression for a given variable into a user-provided buffer
351 // If the variable type is not a pointer, this is simply its size as a decimal constant
352 // If the variable is a pointer, this will be an expression provided by the .attrib file
353 // through the 'len' attribute.
354 //
355 // Returns 1 if the variable is a pointer, 0 otherwise
356 //
getVarEncodingSizeExpression(Var & var,EntryPoint * e,char * buff,size_t bufflen)357 static int getVarEncodingSizeExpression(Var&  var, EntryPoint* e, char* buff, size_t bufflen)
358 {
359     int ret = 0;
360     if (!var.isPointer()) {
361         snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
362     } else {
363         ret = 1;
364         const char* lenExpr = var.lenExpression().c_str();
365         const char* varname = var.name().c_str();
366         if (e != NULL && lenExpr[0] == '\0') {
367             fprintf(stderr, "%s: data len is undefined for '%s'\n",
368                     e->name().c_str(), varname);
369         }
370         if (var.nullAllowed()) {
371             snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
372         } else {
373             snprintf(buff, bufflen, "%s", lenExpr);
374         }
375     }
376     return ret;
377 }
378 
writeVarEncodingSize(Var & var,FILE * fp)379 static int writeVarEncodingSize(Var& var, FILE* fp)
380 {
381     int ret = 0;
382     if (!var.isPointer()) {
383         fprintf(fp, "%u", (unsigned int) var.type()->bytes());
384     } else {
385         ret = 1;
386         fprintf(fp, "__size_%s", var.name().c_str());
387     }
388     return ret;
389 }
390 
391 
392 
writeVarEncodingExpression(Var & var,FILE * fp)393 static void writeVarEncodingExpression(Var& var, FILE* fp)
394 {
395     const char* varname = var.name().c_str();
396 
397     if (var.isPointer()) {
398         // encode a pointer header
399         fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
400 
401         Var::PointerDir dir = var.pointerDir();
402         if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
403             if (var.nullAllowed()) {
404                 fprintf(fp, "\tif (%s != NULL) ", varname);
405             } else {
406                 fprintf(fp, "\t");
407             }
408 
409             if (var.packExpression().size() != 0) {
410                 fprintf(fp, "%s;", var.packExpression().c_str());
411             } else {
412                 fprintf(fp, "memcpy(ptr, %s, __size_%s);",
413                         varname, varname);
414             }
415 
416             fprintf(fp, "ptr += __size_%s;\n", varname);
417         }
418     } else {
419         // encode a non pointer variable
420         if (!var.isVoid()) {
421             fprintf(fp, "\t\tmemcpy(ptr, &%s, %u); ptr += %u;\n",
422                     varname,
423                     (unsigned) var.type()->bytes(),
424                     (unsigned) var.type()->bytes());
425         }
426     }
427 }
428 
429 #if WITH_LARGE_SUPPORT
writeVarLargeEncodingExpression(Var & var,FILE * fp)430 static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
431 {
432     const char* varname = var.name().c_str();
433 
434     fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
435     if (var.nullAllowed()) {
436         fprintf(fp, "\tif (%s != NULL) ", varname);
437     } else {
438         fprintf(fp, "\t");
439     }
440     if (var.writeExpression() != "") {
441         fprintf(fp, "%s", var.writeExpression().c_str());
442     } else {
443         fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname);
444     }
445     fprintf(fp, ";\n");
446 }
447 #endif /* WITH_LARGE_SUPPORT */
448 
genEncoderImpl(const std::string & filename)449 int ApiGen::genEncoderImpl(const std::string &filename)
450 {
451     FILE *fp = fopen(filename.c_str(), "wt");
452     if (fp == NULL) {
453         perror(filename.c_str());
454         return -1;
455     }
456 
457     printHeader(fp);
458     fprintf(fp, "\n\n#include <string.h>\n");
459     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
460     fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
461     fprintf(fp, "#include <stdio.h>\n");
462     std::string classname = m_basename + "_encoder_context_t";
463     size_t n = size();
464 
465     // unsupport printout
466     fprintf(fp,
467             "static void enc_unsupported()\n{\n\tALOGE(\"Function is unsupported\\n\");\n}\n\n");
468 
469     // entry points;
470     for (size_t i = 0; i < n; i++) {
471         EntryPoint *e = &at(i);
472 
473         if (e->unsupported()) continue;
474 
475 
476         e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
477         fprintf(fp, "{\n");
478 
479 //      fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
480         fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
481                 classname.c_str(),
482                 classname.c_str());
483         fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n");
484         VarsArray & evars = e->vars();
485         size_t  maxvars = evars.size();
486         size_t  j;
487 
488         char    buff[256];
489 
490         // Define the __size_XXX variables that contain the size of data
491         // associated with pointers.
492         for (j = 0; j < maxvars; j++) {
493             Var& var = evars[j];
494 
495             if (!var.isPointer())
496                 continue;
497 
498             const char* varname = var.name().c_str();
499             fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
500 
501             getVarEncodingSizeExpression(var, e, buff, sizeof(buff));
502             fprintf(fp, "%s;\n", buff);
503         }
504 
505 #if WITH_LARGE_SUPPORT
506         // We need to take care of 'isLarge' variable in a special way
507         // Anything before an isLarge variable can be packed into a single
508         // buffer, which is then commited. Each isLarge variable is a pointer
509         // to data that can be written to directly through the pipe, which
510         // will be instant when using a QEMU pipe
511 
512         size_t  nvars   = 0;
513         size_t  npointers = 0;
514 
515         // First, compute the total size, 8 bytes for the opcode + payload size
516         fprintf(fp, "\t unsigned char *ptr;\n");
517         fprintf(fp, "\t const size_t packetSize = 8");
518 
519         for (j = 0; j < maxvars; j++) {
520             fprintf(fp, " + ");
521             npointers += writeVarEncodingSize(evars[j], fp);
522         }
523         if (npointers > 0) {
524             fprintf(fp, " + %zu*4", npointers);
525         }
526         fprintf(fp, ";\n");
527 
528         // We need to divide the packet into fragments. Each fragment contains
529         // either copied arguments to a temporary buffer, or direct writes for
530         // large variables.
531         //
532         // The first fragment must also contain the opcode+payload_size
533         //
534         nvars = 0;
535         while (nvars < maxvars || maxvars == 0) {
536 
537             // Skip over non-large fields
538             for (j = nvars; j < maxvars; j++) {
539                 if (evars[j].isLarge())
540                     break;
541             }
542 
543             // Write a fragment if needed.
544             if (nvars == 0 || j > nvars) {
545                 const char* plus = "";
546 
547                 if (nvars == 0 && j == maxvars) {
548                     // Simple shortcut for the common case where we don't have large variables;
549                     fprintf(fp, "\tptr = stream->alloc(packetSize);\n");
550 
551                 } else {
552                     // allocate buffer from the stream until the first large variable
553                     fprintf(fp, "\tptr = stream->alloc(");
554                     plus = "";
555 
556                     if (nvars == 0) {
557                         fprintf(fp,"8"); plus = " + ";
558                     }
559                     if (j > nvars) {
560                         npointers = 0;
561                         for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
562                             fprintf(fp, "%s", plus); plus = " + ";
563                             npointers += writeVarEncodingSize(evars[j], fp);
564                         }
565                         if (npointers > 0) {
566                             fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
567                         }
568                     }
569                     fprintf(fp,");\n");
570                 }
571 
572                 // encode packet header if needed.
573                 if (nvars == 0) {
574                     fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
575                     fprintf(fp, "\tmemcpy(ptr, &packetSize, 4);  ptr += 4;\n\n");
576                 }
577 
578                 if (maxvars == 0)
579                     break;
580 
581                 // encode non-large fields in this fragment
582                 for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
583                     writeVarEncodingExpression(evars[j],fp);
584                 }
585 
586                 // Ensure the fragment is commited if it is followed by a large variable
587                 if (j < maxvars) {
588                     fprintf(fp, "\tstream->flush();\n");
589                 }
590             }
591 
592             // If we have one or more large variables, write them directly.
593             // As size + data
594             for ( ; j < maxvars && evars[j].isLarge(); j++) {
595                 writeVarLargeEncodingExpression(evars[j], fp);
596             }
597 
598             nvars = j;
599         }
600 
601 #else /* !WITH_LARGE_SUPPORT */
602         size_t nvars = evars.size();
603         size_t npointers = 0;
604         fprintf(fp, "\t const size_t packetSize = 8");
605         for (size_t j = 0; j < nvars; j++) {
606             npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
607             fprintf(fp, " + %s", buff);
608         }
609         fprintf(fp, " + %u * 4;\n", (unsigned int) npointers);
610 
611         // allocate buffer from the stream;
612         fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n");
613 
614         // encode into the stream;
615         fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
616         fprintf(fp, "\tmemcpy(ptr, &packetSize, 4);  ptr += 4;\n\n");
617 
618         // out variables
619         for (size_t j = 0; j < nvars; j++) {
620             writeVarEncodingExpression(evars[j], fp);
621         }
622 #endif /* !WITH_LARGE_SUPPORT */
623 
624         // in variables;
625         for (size_t j = 0; j < nvars; j++) {
626             if (evars[j].isPointer()) {
627                 Var::PointerDir dir = evars[j].pointerDir();
628                 if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
629                     const char* varname = evars[j].name().c_str();
630                     if (evars[j].nullAllowed()) {
631                         fprintf(fp, "\tif (%s != NULL) ",varname);
632                     } else {
633                         fprintf(fp, "\t");
634                     }
635                     fprintf(fp, "stream->readback(%s, __size_%s);\n",
636                             varname, varname);
637                 }
638             }
639         }
640 //XXX       fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str());
641         // todo - return value for pointers
642         if (e->retval().isPointer()) {
643             fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
644                     e->name().c_str());
645             fprintf(fp, "\t return NULL;\n");
646         } else if (e->retval().type()->name() != "void") {
647             fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
648             fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes());
649             fprintf(fp, "\treturn retval;\n");
650         }
651         fprintf(fp, "}\n\n");
652     }
653 
654     // constructor
655     fprintf(fp, "%s::%s(IOStream *stream)\n{\n", classname.c_str(), classname.c_str());
656     fprintf(fp, "\tm_stream = stream;\n\n");
657 
658     for (size_t i = 0; i < n; i++) {
659         EntryPoint *e = &at(i);
660         if (e->unsupported()) {
661             fprintf(fp, "\tset_%s((%s_%s_proc_t)(enc_unsupported));\n", e->name().c_str(), e->name().c_str(), sideString(CLIENT_SIDE));
662         } else {
663             fprintf(fp, "\tset_%s(%s_enc);\n", e->name().c_str(), e->name().c_str());
664         }
665         /**
666            if (e->unsupsported()) {
667            fprintf(fp, "\tmemcpy((void *)(&%s), (const void *)(&enc_unsupported), sizeof(%s));\n",
668            e->name().c_str(),
669            e->name().c_str());
670            } else {
671            fprintf(fp, "\t%s = %s_enc;\n", e->name().c_str(), e->name().c_str());
672            }
673         **/
674     }
675     fprintf(fp, "}\n\n");
676 
677     fclose(fp);
678     return 0;
679 }
680 
681 
genDecoderHeader(const std::string & filename)682 int ApiGen::genDecoderHeader(const std::string &filename)
683 {
684     FILE *fp = fopen(filename.c_str(), "wt");
685     if (fp == NULL) {
686         perror(filename.c_str());
687         return -1;
688     }
689 
690     printHeader(fp);
691     std::string classname = m_basename + "_decoder_context_t";
692 
693     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
694     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
695 
696     fprintf(fp, "#include \"IOStream.h\" \n");
697     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
698 
699     for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
700         fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
701     }
702     fprintf(fp, "\n");
703 
704     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
705             classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
706     fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n");
707     fprintf(fp, "\n};\n\n");
708     fprintf(fp, "#endif\n");
709 
710     fclose(fp);
711     return 0;
712 }
713 
genContextImpl(const std::string & filename,SideType side)714 int ApiGen::genContextImpl(const std::string &filename, SideType side)
715 {
716     FILE *fp = fopen(filename.c_str(), "wt");
717     if (fp == NULL) {
718         perror(filename.c_str());
719         return -1;
720     }
721     printHeader(fp);
722 
723     std::string classname = m_basename + "_" + sideString(side) + "_context_t";
724     size_t n = size();
725     fprintf(fp, "\n\n#include <string.h>\n");
726     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
727     fprintf(fp, "#include <stdio.h>\n\n");
728 
729     // init function;
730     fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
731     fprintf(fp, "\tvoid *ptr;\n\n");
732     for (size_t i = 0; i < n; i++) {
733         EntryPoint *e = &at(i);
734         fprintf(fp, "\tptr = getProc(\"%s\", userData); set_%s((%s_%s_proc_t)ptr);\n",
735                 e->name().c_str(),
736                 e->name().c_str(),
737                 e->name().c_str(),
738                 sideString(side));
739 
740     }
741     fprintf(fp, "\treturn 0;\n");
742     fprintf(fp, "}\n\n");
743     fclose(fp);
744     return 0;
745 }
746 
genDecoderImpl(const std::string & filename)747 int ApiGen::genDecoderImpl(const std::string &filename)
748 {
749     FILE *fp = fopen(filename.c_str(), "wt");
750     if (fp == NULL) {
751         perror(filename.c_str());
752         return -1;
753     }
754 
755     printHeader(fp);
756 
757     std::string classname = m_basename + "_decoder_context_t";
758 
759     size_t n = size();
760 
761     fprintf(fp, "\n\n#include <string.h>\n");
762     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
763     fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
764     fprintf(fp, "#include <stdio.h>\n\n");
765     fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
766 
767     // decoder switch;
768     fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
769     fprintf(fp,
770             "                           \n\
771 \tsize_t pos = 0;\n\
772 \tif (len < 8) return pos; \n\
773 \tunsigned char *ptr = (unsigned char *)buf;\n\
774 \tbool unknownOpcode = false;  \n\
775 #ifdef CHECK_GL_ERROR \n\
776 \tchar lastCall[256] = {0}; \n\
777 #endif \n\
778 \twhile ((len - pos >= 8) && !unknownOpcode) {   \n\
779 \t\tint opcode = *(int *)ptr;   \n\
780 \t\tunsigned int packetLen = *(int *)(ptr + 4);\n\
781 \t\tif (len - pos < packetLen)  return pos; \n\
782 \t\tswitch(opcode) {\n");
783 
784     for (size_t f = 0; f < n; f++) {
785         enum Pass_t { PASS_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST };
786         EntryPoint *e = &at(f);
787 
788         // construct a printout string;
789         std::string printString = "";
790         for (size_t i = 0; i < e->vars().size(); i++) {
791             Var *v = &e->vars()[i];
792             if (!v->isVoid())  printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
793         }
794         printString += "";
795         // TODO - add for return value;
796 
797         fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str());
798         fprintf(fp, "\t\t\t{\n");
799 
800         bool totalTmpBuffExist = false;
801         std::string totalTmpBuffOffset = "0";
802         std::string *tmpBufOffset = new std::string[e->vars().size()];
803 
804         // construct retval type string
805         std::string retvalType;
806         if (!e->retval().isVoid()) {
807             retvalType = e->retval().type()->name();
808         }
809 
810         for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
811             if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
812                 fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
813                         totalTmpBuffOffset.c_str());
814             }
815 
816 
817             if (pass == PASS_FunctionCall) {
818                 fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
819                 if (e->customDecoder()) {
820                     fprintf(fp, "this"); // add a context to the call
821                 }
822             } else if (pass == PASS_DebugPrint) {
823                 fprintf(fp, "#ifdef DEBUG_PRINTOUT\n");
824                 fprintf(fp, "\t\t\tfprintf(stderr,\"%s(%%p): %s(%s)\\n\", stream",
825                         m_basename.c_str(), e->name().c_str(), printString.c_str());
826                 if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ",");
827             }
828 
829             std::string varoffset = "8"; // skip the header
830             VarsArray & evars = e->vars();
831             // allocate memory for out pointers;
832             for (size_t j = 0; j < evars.size(); j++) {
833                 Var *v = & evars[j];
834                 if (!v->isVoid()) {
835                     if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", ");
836                     if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", ");
837 
838                     if (!v->isPointer()) {
839                         if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
840                             fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
841                         }
842                         varoffset += " + " + toString(v->type()->bytes());
843                     } else {
844                         if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) {
845                             if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) {
846                                 fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
847                                         (unsigned) j, varoffset.c_str());
848                                 fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
849                                         (unsigned) j, varoffset.c_str());
850                             }
851                             if (pass == PASS_FunctionCall) {
852                                 if (v->nullAllowed()) {
853                                     fprintf(fp, "*((unsigned int *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)",
854                                             varoffset.c_str(), v->type()->name().c_str(), varoffset.c_str());
855                                 } else {
856                                     fprintf(fp, "(%s)(ptr + %s + 4)",
857                                             v->type()->name().c_str(), varoffset.c_str());
858                                 }
859                             } else if (pass == PASS_DebugPrint) {
860                                 fprintf(fp, "(%s)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
861                                         v->type()->name().c_str(), varoffset.c_str(),
862                                         varoffset.c_str());
863                             }
864                             varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")";
865                         } else { // out pointer;
866                             if (pass == PASS_TmpBuffAlloc) {
867                                 fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
868                                         (unsigned) j, varoffset.c_str());
869                                 if (!totalTmpBuffExist) {
870                                     fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (unsigned)j);
871                                 } else {
872                                     fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (unsigned)j);
873                                 }
874                                 tmpBufOffset[j] = totalTmpBuffOffset;
875                                 char tmpPtrName[16];
876                                 sprintf(tmpPtrName," + tmpPtr%uSize", (unsigned)j);
877                                 totalTmpBuffOffset += std::string(tmpPtrName);
878                                 totalTmpBuffExist = true;
879                             } else if (pass == PASS_MemAlloc) {
880                                 fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
881                                         (unsigned)j, tmpBufOffset[j].c_str());
882                                 fprintf(fp, "\t\t\tmemset(tmpPtr%u, 0, %s);\n",
883                                         (unsigned)j,
884                                         toString(v->type()->bytes()).c_str());
885                             } else if (pass == PASS_FunctionCall) {
886                                 if (v->nullAllowed()) {
887                                     fprintf(fp, "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)",
888                                             (unsigned) j, v->type()->name().c_str(), (unsigned) j);
889                                 } else {
890                                     fprintf(fp, "(%s)(tmpPtr%u)", v->type()->name().c_str(), (unsigned) j);
891                                 }
892                             } else if (pass == PASS_DebugPrint) {
893                                 fprintf(fp, "(%s)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
894                                         v->type()->name().c_str(), (unsigned) j,
895                                         varoffset.c_str());
896                             }
897                             varoffset += " + 4";
898                         }
899                     }
900                 }
901             }
902 
903             if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
904             if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
905 
906             if (pass == PASS_TmpBuffAlloc) {
907                 if (!e->retval().isVoid() && !e->retval().isPointer()) {
908                     if (!totalTmpBuffExist)
909                         fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str());
910                     else
911                         fprintf(fp, "\t\t\ttotalTmpSize += sizeof(%s);\n", retvalType.c_str());
912 
913                     totalTmpBuffExist = true;
914                 }
915                 if (totalTmpBuffExist) {
916                     fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
917                 }
918             }
919 
920             if (pass == PASS_Epilog) {
921                 // send back out pointers data as well as retval
922                 if (totalTmpBuffExist) {
923                     fprintf(fp, "\t\t\tstream->flush();\n");
924                 }
925 
926                 fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
927                 fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
928             }
929 
930         } // pass;
931         fprintf(fp, "\t\t\t}\n");
932         fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
933         fprintf(fp, "\t\t\tsprintf(lastCall, \"%s\");\n", e->name().c_str());
934         fprintf(fp, "#endif\n");
935         fprintf(fp, "\t\t\tbreak;\n");
936 
937         delete [] tmpBufOffset;
938     }
939     fprintf(fp, "\t\t\tdefault:\n");
940     fprintf(fp, "\t\t\t\tunknownOpcode = true;\n");
941     fprintf(fp, "\t\t} //switch\n");
942     if (strstr(m_basename.c_str(), "gl")) {
943         fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
944         fprintf(fp, "\tint err = lastCall[0] ? this->glGetError() : GL_NO_ERROR;\n");
945         fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
946         fprintf(fp, "#endif\n");
947     }
948     fprintf(fp, "\t} // while\n");
949     fprintf(fp, "\treturn pos;\n");
950     fprintf(fp, "}\n");
951 
952     fclose(fp);
953     return 0;
954 }
955 
readSpec(const std::string & filename)956 int ApiGen::readSpec(const std::string & filename)
957 {
958     FILE *specfp = fopen(filename.c_str(), "rt");
959     if (specfp == NULL) {
960         return -1;
961     }
962 
963     char line[1000];
964     unsigned int lc = 0;
965     while (fgets(line, sizeof(line), specfp) != NULL) {
966         lc++;
967         EntryPoint ref;
968         if (ref.parse(lc, std::string(line))) {
969             push_back(ref);
970             updateMaxEntryPointsParams(ref.vars().size());
971         }
972     }
973     fclose(specfp);
974     return 0;
975 }
976 
readAttributes(const std::string & attribFilename)977 int ApiGen::readAttributes(const std::string & attribFilename)
978 {
979     enum { ST_NAME, ST_ATT } state;
980 
981     FILE *fp = fopen(attribFilename.c_str(), "rt");
982     if (fp == NULL) {
983         perror(attribFilename.c_str());
984         return -1;
985     }
986     char buf[1000];
987 
988     state = ST_NAME;
989     EntryPoint *currentEntry = NULL;
990     size_t lc = 0;
991     bool globalAttributes = false;
992     while (fgets(buf, sizeof(buf), fp) != NULL) {
993         lc++;
994         std::string line(buf);
995         if (line.size() == 0) continue; // could that happen?
996 
997         if (line.at(0) == '#') continue; // comment
998 
999         size_t first = line.find_first_not_of(" \t\n");
1000         if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
1001 
1002         line = trim(line);
1003         if (line.size() == 0 || line.at(0) == '#') continue;
1004 
1005         switch(state) {
1006         case ST_NAME:
1007             if (line == "GLOBAL") {
1008                 globalAttributes = true;
1009             } else {
1010                 globalAttributes = false;
1011                 currentEntry = findEntryByName(line);
1012                 if (currentEntry == NULL) {
1013                     fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
1014                 }
1015             }
1016             state = ST_ATT;
1017             break;
1018         case ST_ATT:
1019             if (globalAttributes) {
1020                 setGlobalAttribute(line, lc);
1021             } else  if (currentEntry != NULL) {
1022                 currentEntry->setAttribute(line, lc);
1023             }
1024             break;
1025         }
1026     }
1027     return 0;
1028 }
1029 
1030 
setGlobalAttribute(const std::string & line,size_t lc)1031 int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
1032 {
1033     size_t pos = 0;
1034     size_t last;
1035     std::string token = getNextToken(line, pos, &last, WHITESPACE);
1036     pos = last;
1037 
1038     if (token == "base_opcode") {
1039         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1040         if (str.size() == 0) {
1041             fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc);
1042         } else {
1043             setBaseOpcode(atoi(str.c_str()));
1044         }
1045     } else  if (token == "encoder_headers") {
1046         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1047         pos = last;
1048         while (str.size() != 0) {
1049             encoderHeaders().push_back(str);
1050             str = getNextToken(line, pos, &last, WHITESPACE);
1051             pos = last;
1052         }
1053     } else if (token == "client_context_headers") {
1054         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1055         pos = last;
1056         while (str.size() != 0) {
1057             clientContextHeaders().push_back(str);
1058             str = getNextToken(line, pos, &last, WHITESPACE);
1059             pos = last;
1060         }
1061     } else if (token == "server_context_headers") {
1062         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1063         pos = last;
1064         while (str.size() != 0) {
1065             serverContextHeaders().push_back(str);
1066             str = getNextToken(line, pos, &last, WHITESPACE);
1067             pos = last;
1068         }
1069     } else if (token == "decoder_headers") {
1070         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1071         pos = last;
1072         while (str.size() != 0) {
1073             decoderHeaders().push_back(str);
1074             str = getNextToken(line, pos, &last, WHITESPACE);
1075             pos = last;
1076         }
1077     }
1078     else {
1079         fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
1080     }
1081 
1082     return 0;
1083 }
1084 
1085