static void writeVarEncodingExpression(Var& var, FILE* fp) { const char* varname = var.name().c_str(); if (var.isPointer()) { // encode a pointer header fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname); Var::PointerDir dir = var.pointerDir(); if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) { if (var.nullAllowed()) { fprintf(fp, "\tif (%s != NULL) ", varname); } else { fprintf(fp, "\t"); } if (var.packExpression().size() != 0) { fprintf(fp, "%s;", var.packExpression().c_str()); } else { fprintf(fp, "memcpy(ptr, %s, __size_%s);", varname, varname); } fprintf(fp, "ptr += __size_%s;\n", varname); } } else { // encode a non pointer variable if (!var.isVoid()) { fprintf(fp, "\t\tmemcpy(ptr, &%s, %u); ptr += %u;\n", varname, (unsigned) var.type()->bytes(), (unsigned) var.type()->bytes()); } } }
int ApiGen::genDecoderImpl(const std::string &filename) { FILE *fp = fopen(filename.c_str(), "wt"); if (fp == NULL) { perror(filename.c_str()); return -1; } printHeader(fp); std::string classname = m_basename + "_decoder_context_t"; size_t n = size(); fprintf(fp, "\n\n#include <string.h>\n"); fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str()); fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str()); fprintf(fp, "#include \"ProtocolUtils.h\"\n\n"); fprintf(fp, "#include <stdio.h>\n\n"); 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"); // helper macros fprintf(fp, "#ifdef DEBUG_PRINTOUT\n" "# define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n" "#else\n" "# define DEBUG(...) ((void)0)\n" "#endif\n\n"); fprintf(fp, "#ifdef CHECK_GLERROR\n" "# define SET_LASTCALL(name) sprintf(lastCall, #name)\n" "#else\n" "# define SET_LASTCALL(name) ((void)0)\n" "#endif\n\n"); // helper templates fprintf(fp, "using namespace emugl;\n\n"); // decoder switch; fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str()); fprintf(fp, " \n\ \tsize_t pos = 0;\n\ \tif (len < 8) return pos; \n\ \tunsigned char *ptr = (unsigned char *)buf;\n\ \tbool unknownOpcode = false; \n\ #ifdef CHECK_GL_ERROR \n\ \tchar lastCall[256] = {0}; \n\ #endif \n\ \twhile ((len - pos >= 8) && !unknownOpcode) { \n\ \t\tuint32_t opcode = *(uint32_t *)ptr; \n\ \t\tsize_t packetLen = *(uint32_t *)(ptr + 4);\n\ \t\tif (len - pos < packetLen) return pos; \n\ \t\tswitch(opcode) {\n"); for (size_t f = 0; f < n; f++) { enum Pass_t { PASS_FIRST = 0, PASS_VariableDeclarations = PASS_FIRST, PASS_TmpBuffAlloc, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_FlushOutput, PASS_Epilog, PASS_LAST }; EntryPoint *e = &at(f); // construct a printout string; std::string printString = ""; for (size_t i = 0; i < e->vars().size(); i++) { Var *v = &e->vars()[i]; if (!v->isVoid()) printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " "; } printString += ""; // TODO - add for return value; fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str()); bool totalTmpBuffExist = false; std::string totalTmpBuffOffset = "0"; std::string *tmpBufOffset = new std::string[e->vars().size()]; // construct retval type string std::string retvalType; if (!e->retval().isVoid()) { retvalType = e->retval().type()->name(); } for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) { if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) { fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(), totalTmpBuffOffset.c_str()); } if (pass == PASS_FunctionCall) { fprintf(fp, "\t\t\tthis->%s(", e->name().c_str()); if (e->customDecoder()) { fprintf(fp, "this"); // add a context to the call } } else if (pass == PASS_DebugPrint) { fprintf(fp, "\t\t\tDEBUG(\"%s(%%p): %s(%s)\\n\", stream", m_basename.c_str(), e->name().c_str(), printString.c_str()); if (e->vars().size() > 0 && !e->vars()[0].isVoid()) { fprintf(fp, ","); } } std::string varoffset = "8"; // skip the header VarsArray & evars = e->vars(); // allocate memory for out pointers; for (size_t j = 0; j < evars.size(); j++) { Var *v = & evars[j]; if (v->isVoid()) { continue; } const char* var_name = v->name().c_str(); const char* var_type_name = v->type()->name().c_str(); const unsigned var_type_bytes = v->type()->bytes(); if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) { fprintf(fp, ", "); } if (pass == PASS_DebugPrint && j != 0) { fprintf(fp, ", "); } if (!v->isPointer()) { if (pass == PASS_VariableDeclarations) { fprintf(fp, "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n", var_type_name, var_name, var_type_name, var_type_bytes * 8U, varoffset.c_str()); } if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) { fprintf(fp, "var_%s", var_name); } varoffset += " + " + toString(var_type_bytes); continue; } if (pass == PASS_VariableDeclarations) { fprintf(fp, "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n", var_name, varoffset.c_str()); } if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) { if (pass == PASS_VariableDeclarations) { #if USE_ALIGNED_BUFFERS fprintf(fp, "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n", var_name, varoffset.c_str(), var_name); } if (pass == PASS_FunctionCall) { if (v->nullAllowed()) { fprintf(fp, "size_%s == 0 ? NULL : (%s)(inptr_%s.get())", var_name, var_type_name, var_name); } else { fprintf(fp, "(%s)(inptr_%s.get())", var_type_name, var_name); } } else if (pass == PASS_DebugPrint) { fprintf(fp, "(%s)(inptr_%s.get()), size_%s", var_type_name, var_name, var_name); } #else // !USE_ALIGNED_BUFFERS fprintf(fp, "unsigned char *inptr_%s = (ptr + %s + 4);\n", var_name, varoffset.c_str()); } if (pass == PASS_FunctionCall) { if (v->nullAllowed()) { fprintf(fp, "size_%s == 0 ? NULL : (%s)(inptr_%s)", var_name, var_type_name, var_name); } else { fprintf(fp, "(%s)(inptr_%s)", var_type_name, var_name); } } else if (pass == PASS_DebugPrint) { fprintf(fp, "(%s)(inptr_%s), size_%s", var_type_name, var_name, var_name); } #endif // !USE_ALIGNED_BUFFERS varoffset += " + 4 + size_"; varoffset += var_name; } else { // out pointer; if (pass == PASS_TmpBuffAlloc) { if (!totalTmpBuffExist) { fprintf(fp, "\t\t\tsize_t totalTmpSize = size_%s;\n", var_name); } else { fprintf(fp, "\t\t\ttotalTmpSize += size_%s;\n", var_name); } tmpBufOffset[j] = totalTmpBuffOffset; totalTmpBuffOffset += " + size_"; totalTmpBuffOffset += var_name; totalTmpBuffExist = true; } else if (pass == PASS_MemAlloc) { #if USE_ALIGNED_BUFFERS fprintf(fp, "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n", var_name, tmpBufOffset[j].c_str(), var_name); } else if (pass == PASS_FunctionCall) { if (v->nullAllowed()) { fprintf(fp, "size_%s == 0 ? NULL : (%s)(outptr_%s.get())", var_name, var_type_name, var_name); } else { fprintf(fp, "(%s)(outptr_%s.get())", var_type_name, var_name); } } else if (pass == PASS_DebugPrint) { fprintf(fp, "(%s)(outptr_%s.get()), size_%s", var_type_name, var_name, var_name); } if (pass == PASS_FlushOutput) { fprintf(fp, "\t\t\toutptr_%s.flush();\n", var_name); } #else // !USE_ALIGNED_BUFFERS fprintf(fp, "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n", var_name, tmpBufOffset[j].c_str()); fprintf(fp, "\t\t\tmemset(outptr_%s, 0, %s);\n", var_name, toString(v->type()->bytes()).c_str()); } else if (pass == PASS_FunctionCall) { if (v->nullAllowed()) { fprintf(fp, "size_%s == 0 ? NULL : (%s)(outptr_%s)", var_name, var_type_name, var_name); } else { fprintf(fp, "(%s)(outptr_%s)", var_type_name, var_name); } } else if (pass == PASS_DebugPrint) { fprintf(fp, "(%s)(outptr_%s), size_%s", var_type_name, var_name, varoffset.c_str()); } #endif // !USE_ALIGNED_BUFFERS varoffset += " + 4"; }