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