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 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 47 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 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 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 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 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 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 } 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 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 // 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 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 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 (uint) var.type()->bytes(), 424 (uint) var.type()->bytes()); 425 } 426 } 427 } 428 429 #if WITH_LARGE_SUPPORT 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 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",(uint) 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 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 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 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\tvoid *params[%u]; \n\ 780 \t\tint opcode = *(int *)ptr; \n\ 781 \t\tunsigned int packetLen = *(int *)(ptr + 4);\n\ 782 \t\tif (len - pos < packetLen) return pos; \n\ 783 \t\tswitch(opcode) {\n", 784 (uint) m_maxEntryPointsParams); 785 786 for (size_t f = 0; f < n; f++) { 787 enum Pass_t { PASS_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST }; 788 EntryPoint *e = &at(f); 789 790 // construct a printout string; 791 std::string printString = ""; 792 for (size_t i = 0; i < e->vars().size(); i++) { 793 Var *v = &e->vars()[i]; 794 if (!v->isVoid()) printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " "; 795 } 796 printString += ""; 797 // TODO - add for return value; 798 799 fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str()); 800 fprintf(fp, "\t\t\t{\n"); 801 802 bool totalTmpBuffExist = false; 803 std::string totalTmpBuffOffset = "0"; 804 std::string *tmpBufOffset = new std::string[e->vars().size()]; 805 806 // construct retval type string 807 std::string retvalType; 808 if (!e->retval().isVoid()) { 809 retvalType = e->retval().type()->name(); 810 } 811 812 for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) { 813 if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) { 814 fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(), 815 totalTmpBuffOffset.c_str()); 816 } 817 818 819 if (pass == PASS_FunctionCall) { 820 fprintf(fp, "\t\t\tthis->%s(", e->name().c_str()); 821 if (e->customDecoder()) { 822 fprintf(fp, "this"); // add a context to the call 823 } 824 } else if (pass == PASS_DebugPrint) { 825 fprintf(fp, "#ifdef DEBUG_PRINTOUT\n"); 826 fprintf(fp, "\t\t\tfprintf(stderr,\"%s: %s(%s)\\n\"", m_basename.c_str(), e->name().c_str(), printString.c_str()); 827 if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ","); 828 } 829 830 std::string varoffset = "8"; // skip the header 831 VarsArray & evars = e->vars(); 832 // allocate memory for out pointers; 833 for (size_t j = 0; j < evars.size(); j++) { 834 Var *v = & evars[j]; 835 if (!v->isVoid()) { 836 if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", "); 837 if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", "); 838 839 if (!v->isPointer()) { 840 if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) { 841 fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str()); 842 } 843 varoffset += " + " + toString(v->type()->bytes()); 844 } else { 845 if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) { 846 if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) { 847 fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n", 848 (uint) j, varoffset.c_str()); 849 fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n", 850 (uint) j, varoffset.c_str()); 851 } 852 if (pass == PASS_FunctionCall) { 853 if (v->nullAllowed()) { 854 fprintf(fp, "*((unsigned int *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)", 855 varoffset.c_str(), v->type()->name().c_str(), varoffset.c_str()); 856 } else { 857 fprintf(fp, "(%s)(ptr + %s + 4)", 858 v->type()->name().c_str(), varoffset.c_str()); 859 } 860 } else if (pass == PASS_DebugPrint) { 861 fprintf(fp, "(%s)(ptr + %s + 4), *(unsigned int *)(ptr + %s)", 862 v->type()->name().c_str(), varoffset.c_str(), 863 varoffset.c_str()); 864 } 865 varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")"; 866 } else { // out pointer; 867 if (pass == PASS_TmpBuffAlloc) { 868 fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n", 869 (uint) j, varoffset.c_str()); 870 if (!totalTmpBuffExist) { 871 fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (uint)j); 872 } else { 873 fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (uint)j); 874 } 875 tmpBufOffset[j] = totalTmpBuffOffset; 876 char tmpPtrName[16]; 877 sprintf(tmpPtrName," + tmpPtr%uSize", (uint)j); 878 totalTmpBuffOffset += std::string(tmpPtrName); 879 totalTmpBuffExist = true; 880 } else if (pass == PASS_MemAlloc) { 881 fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n", 882 (uint)j, tmpBufOffset[j].c_str()); 883 } else if (pass == PASS_FunctionCall) { 884 if (v->nullAllowed()) { 885 fprintf(fp, "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)", 886 (uint) j, v->type()->name().c_str(), (uint) j); 887 } else { 888 fprintf(fp, "(%s)(tmpPtr%u)", v->type()->name().c_str(), (uint) j); 889 } 890 } else if (pass == PASS_DebugPrint) { 891 fprintf(fp, "(%s)(tmpPtr%u), *(unsigned int *)(ptr + %s)", 892 v->type()->name().c_str(), (uint) j, 893 varoffset.c_str()); 894 } 895 varoffset += " + 4"; 896 } 897 } 898 } 899 } 900 901 if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n"); 902 if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n"); 903 904 if (pass == PASS_TmpBuffAlloc) { 905 if (!e->retval().isVoid() && !e->retval().isPointer()) { 906 if (!totalTmpBuffExist) 907 fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str()); 908 else 909 fprintf(fp, "\t\t\ttotalTmpSize += sizeof(%s);\n", retvalType.c_str()); 910 911 totalTmpBuffExist = true; 912 } 913 if (totalTmpBuffExist) { 914 fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n"); 915 } 916 } 917 918 if (pass == PASS_Epilog) { 919 // send back out pointers data as well as retval 920 if (totalTmpBuffExist) { 921 fprintf(fp, "\t\t\tstream->flush();\n"); 922 } 923 924 fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n"); 925 fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n"); 926 } 927 928 } // pass; 929 fprintf(fp, "\t\t\t}\n"); 930 fprintf(fp, "#ifdef CHECK_GL_ERROR\n"); 931 fprintf(fp, "\t\t\tsprintf(lastCall, \"%s\");\n", e->name().c_str()); 932 fprintf(fp, "#endif\n"); 933 fprintf(fp, "\t\t\tbreak;\n"); 934 935 delete [] tmpBufOffset; 936 } 937 fprintf(fp, "\t\t\tdefault:\n"); 938 fprintf(fp, "\t\t\t\tunknownOpcode = true;\n"); 939 fprintf(fp, "\t\t} //switch\n"); 940 if (strstr(m_basename.c_str(), "gl")) { 941 fprintf(fp, "#ifdef CHECK_GL_ERROR\n"); 942 fprintf(fp, "\tint err = this->glGetError();\n"); 943 fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str()); 944 fprintf(fp, "#endif\n"); 945 } 946 fprintf(fp, "\t} // while\n"); 947 fprintf(fp, "\treturn pos;\n"); 948 fprintf(fp, "}\n"); 949 950 fclose(fp); 951 return 0; 952 } 953 954 int ApiGen::readSpec(const std::string & filename) 955 { 956 FILE *specfp = fopen(filename.c_str(), "rt"); 957 if (specfp == NULL) { 958 return -1; 959 } 960 961 char line[1000]; 962 unsigned int lc = 0; 963 while (fgets(line, sizeof(line), specfp) != NULL) { 964 lc++; 965 EntryPoint ref; 966 if (ref.parse(lc, std::string(line))) { 967 push_back(ref); 968 updateMaxEntryPointsParams(ref.vars().size()); 969 } 970 } 971 fclose(specfp); 972 return 0; 973 } 974 975 int ApiGen::readAttributes(const std::string & attribFilename) 976 { 977 enum { ST_NAME, ST_ATT } state; 978 979 FILE *fp = fopen(attribFilename.c_str(), "rt"); 980 if (fp == NULL) { 981 perror(attribFilename.c_str()); 982 return -1; 983 } 984 char buf[1000]; 985 986 state = ST_NAME; 987 EntryPoint *currentEntry = NULL; 988 size_t lc = 0; 989 bool globalAttributes = false; 990 while (fgets(buf, sizeof(buf), fp) != NULL) { 991 lc++; 992 std::string line(buf); 993 if (line.size() == 0) continue; // could that happen? 994 995 if (line.at(0) == '#') continue; // comment 996 997 size_t first = line.find_first_not_of(" \t\n"); 998 if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME; 999 1000 line = trim(line); 1001 if (line.size() == 0 || line.at(0) == '#') continue; 1002 1003 switch(state) { 1004 case ST_NAME: 1005 if (line == "GLOBAL") { 1006 globalAttributes = true; 1007 } else { 1008 globalAttributes = false; 1009 currentEntry = findEntryByName(line); 1010 if (currentEntry == NULL) { 1011 fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str()); 1012 } 1013 } 1014 state = ST_ATT; 1015 break; 1016 case ST_ATT: 1017 if (globalAttributes) { 1018 setGlobalAttribute(line, lc); 1019 } else if (currentEntry != NULL) { 1020 currentEntry->setAttribute(line, lc); 1021 } 1022 break; 1023 } 1024 } 1025 return 0; 1026 } 1027 1028 1029 int ApiGen::setGlobalAttribute(const std::string & line, size_t lc) 1030 { 1031 size_t pos = 0; 1032 size_t last; 1033 std::string token = getNextToken(line, pos, &last, WHITESPACE); 1034 pos = last; 1035 1036 if (token == "base_opcode") { 1037 std::string str = getNextToken(line, pos, &last, WHITESPACE); 1038 if (str.size() == 0) { 1039 fprintf(stderr, "line %u: missing value for base_opcode\n", (uint) lc); 1040 } else { 1041 setBaseOpcode(atoi(str.c_str())); 1042 } 1043 } else if (token == "encoder_headers") { 1044 std::string str = getNextToken(line, pos, &last, WHITESPACE); 1045 pos = last; 1046 while (str.size() != 0) { 1047 encoderHeaders().push_back(str); 1048 str = getNextToken(line, pos, &last, WHITESPACE); 1049 pos = last; 1050 } 1051 } else if (token == "client_context_headers") { 1052 std::string str = getNextToken(line, pos, &last, WHITESPACE); 1053 pos = last; 1054 while (str.size() != 0) { 1055 clientContextHeaders().push_back(str); 1056 str = getNextToken(line, pos, &last, WHITESPACE); 1057 pos = last; 1058 } 1059 } else if (token == "server_context_headers") { 1060 std::string str = getNextToken(line, pos, &last, WHITESPACE); 1061 pos = last; 1062 while (str.size() != 0) { 1063 serverContextHeaders().push_back(str); 1064 str = getNextToken(line, pos, &last, WHITESPACE); 1065 pos = last; 1066 } 1067 } else if (token == "decoder_headers") { 1068 std::string str = getNextToken(line, pos, &last, WHITESPACE); 1069 pos = last; 1070 while (str.size() != 0) { 1071 decoderHeaders().push_back(str); 1072 str = getNextToken(line, pos, &last, WHITESPACE); 1073 pos = last; 1074 } 1075 } 1076 else { 1077 fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str()); 1078 } 1079 1080 return 0; 1081 } 1082 1083