int ApiGen::genEncoderImpl(const std::string &filename) { FILE *fp = fopen(filename.c_str(), "wt"); if (fp == NULL) { perror(filename.c_str()); return -1; } printHeader(fp); fprintf(fp, "\n\n#include <string.h>\n"); fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str()); fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str()); fprintf(fp, "#include <stdio.h>\n\n"); fprintf(fp, "namespace {\n\n"); // unsupport printout fprintf(fp, "void enc_unsupported()\n" "{\n" "\tALOGE(\"Function is unsupported\\n\");\n" "}\n\n"); // entry points; std::string classname = m_basename + "_encoder_context_t"; size_t n = size(); for (size_t i = 0; i < n; i++) { EntryPoint *e = &at(i); if (e->unsupported()) continue; e->print(fp, true, "_enc", /* classname + "::" */"", "void *self"); fprintf(fp, "{\n"); // fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str()); fprintf(fp, "\n\t%s *ctx = (%s *)self;\n", classname.c_str(), classname.c_str()); fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n"); VarsArray & evars = e->vars(); size_t maxvars = evars.size(); size_t j; char buff[256]; // Define the __size_XXX variables that contain the size of data // associated with pointers. for (j = 0; j < maxvars; j++) { Var& var = evars[j]; if (!var.isPointer()) continue; const char* varname = var.name().c_str(); fprintf(fp, "\tconst unsigned int __size_%s = ", varname); getVarEncodingSizeExpression(var, e, buff, sizeof(buff)); fprintf(fp, "%s;\n", buff); } #if WITH_LARGE_SUPPORT // We need to take care of 'isLarge' variable in a special way // Anything before an isLarge variable can be packed into a single // buffer, which is then commited. Each isLarge variable is a pointer // to data that can be written to directly through the pipe, which // will be instant when using a QEMU pipe size_t nvars = 0; size_t npointers = 0; // First, compute the total size, 8 bytes for the opcode + payload size fprintf(fp, "\t unsigned char *ptr;\n"); fprintf(fp, "\t const size_t packetSize = 8"); for (j = 0; j < maxvars; j++) { fprintf(fp, " + "); npointers += writeVarEncodingSize(evars[j], fp); } if (npointers > 0) { fprintf(fp, " + %zu*4", npointers); } fprintf(fp, ";\n"); // We need to divide the packet into fragments. Each fragment contains // either copied arguments to a temporary buffer, or direct writes for // large variables. // // The first fragment must also contain the opcode+payload_size // nvars = 0; while (nvars < maxvars || maxvars == 0) { // Skip over non-large fields for (j = nvars; j < maxvars; j++) { if (evars[j].isLarge()) break; } // Write a fragment if needed. if (nvars == 0 || j > nvars) { const char* plus = ""; if (nvars == 0 && j == maxvars) { // Simple shortcut for the common case where we don't have large variables; fprintf(fp, "\tptr = stream->alloc(packetSize);\n"); } else { // allocate buffer from the stream until the first large variable fprintf(fp, "\tptr = stream->alloc("); plus = ""; if (nvars == 0) { fprintf(fp,"8"); plus = " + "; } if (j > nvars) { npointers = 0; for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) { fprintf(fp, "%s", plus); plus = " + "; npointers += writeVarEncodingSize(evars[j], fp); } if (npointers > 0) { fprintf(fp, "%s%zu*4", plus, npointers); plus = " + "; } } fprintf(fp,");\n"); } // encode packet header if needed. if (nvars == 0) { fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str()); fprintf(fp, "\tmemcpy(ptr, &packetSize, 4); ptr += 4;\n\n"); } if (maxvars == 0) break; // encode non-large fields in this fragment for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) { writeVarEncodingExpression(evars[j],fp); } // Ensure the fragment is commited if it is followed by a large variable if (j < maxvars) { fprintf(fp, "\tstream->flush();\n"); } } // If we have one or more large variables, write them directly. // As size + data for ( ; j < maxvars && evars[j].isLarge(); j++) { writeVarLargeEncodingExpression(evars[j], fp); } nvars = j; } #else /* !WITH_LARGE_SUPPORT */ size_t nvars = evars.size(); size_t npointers = 0; fprintf(fp, "\t const size_t packetSize = 8"); for (size_t j = 0; j < nvars; j++) { npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff)); fprintf(fp, " + %s", buff); } fprintf(fp, " + %u * 4;\n", (unsigned int) npointers); // allocate buffer from the stream; fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n"); // encode into the stream; fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str()); fprintf(fp, "\tmemcpy(ptr, &packetSize, 4); ptr += 4;\n\n"); // out variables for (size_t j = 0; j < nvars; j++) { writeVarEncodingExpression(evars[j], fp); } #endif /* !WITH_LARGE_SUPPORT */ // in variables; for (size_t j = 0; j < nvars; j++) { if (evars[j].isPointer()) { Var::PointerDir dir = evars[j].pointerDir(); if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) { const char* varname = evars[j].name().c_str(); if (evars[j].nullAllowed()) { fprintf(fp, "\tif (%s != NULL) ",varname); } else { fprintf(fp, "\t"); } fprintf(fp, "stream->readback(%s, __size_%s);\n", varname, varname); } } } //XXX fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str()); // todo - return value for pointers if (e->retval().isPointer()) { fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n", e->name().c_str()); if (e->flushOnEncode()) { fprintf(fp, "\tstream->flush();\n"); } fprintf(fp, "\t return NULL;\n"); } else if (e->retval().type()->name() != "void") { fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str()); fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes()); fprintf(fp, "\treturn retval;\n"); } else if (e->flushOnEncode()) { fprintf(fp, "\tstream->flush();\n"); } fprintf(fp, "}\n\n"); } fprintf(fp, "} // namespace\n\n"); // constructor fprintf(fp, "%s::%s(IOStream *stream)\n{\n", classname.c_str(), classname.c_str()); fprintf(fp, "\tm_stream = stream;\n\n"); for (size_t i = 0; i < n; i++) { EntryPoint *e = &at(i); if (e->unsupported()) { fprintf(fp, "\tthis->%s = (%s_%s_proc_t) &enc_unsupported;\n", e->name().c_str(), e->name().c_str(), sideString(CLIENT_SIDE)); } else { fprintf(fp, "\tthis->%s = &%s_enc;\n", e->name().c_str(), e->name().c_str()); } } fprintf(fp, "}\n\n"); fclose(fp); return 0; }
int ApiGen::genEntryPoints(const std::string & filename, SideType side) { if (side != CLIENT_SIDE && side != WRAPPER_SIDE) { fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n"); return -999; } FILE *fp = fopen(filename.c_str(), "wt"); if (fp == NULL) { perror(filename.c_str()); return errno; } printHeader(fp); fprintf(fp, "#include <stdio.h>\n"); fprintf(fp, "#include <stdlib.h>\n"); fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side)); fprintf(fp, "\n"); fprintf(fp, "#ifndef GL_TRUE\n"); fprintf(fp, "extern \"C\" {\n"); for (size_t i = 0; i < size(); i++) { fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n"); } fprintf(fp, "};\n\n"); fprintf(fp, "#endif\n"); fprintf(fp, "#ifndef GET_CONTEXT\n"); fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n", m_basename.c_str(), sideString(side)); fprintf(fp, "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n", m_basename.c_str(), sideString(side)); fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext()\n", m_basename.c_str(), sideString(side)); fprintf(fp, "#endif\n\n"); for (size_t i = 0; i < size(); i++) { EntryPoint *e = &at(i); e->print(fp); fprintf(fp, "{\n"); fprintf(fp, "\tGET_CONTEXT;\n"); bool shouldReturn = !e->retval().isVoid(); bool shouldCallWithContext = (side == CLIENT_SIDE); //param check if (shouldCallWithContext) { for (size_t j=0; j<e->vars().size(); j++) { if (e->vars()[j].paramCheckExpression() != "") fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str()); } } fprintf(fp, "\t%sctx->%s(%s", shouldReturn ? "return " : "", e->name().c_str(), shouldCallWithContext ? "ctx" : ""); size_t nvars = e->vars().size(); for (size_t j = 0; j < nvars; j++) { if (!e->vars()[j].isVoid()) { fprintf(fp, "%s %s", j != 0 || shouldCallWithContext ? "," : "", e->vars()[j].name().c_str()); } } fprintf(fp, ");\n"); fprintf(fp, "}\n\n"); } fclose(fp); return 0; }