diff options
Diffstat (limited to 'emulator/opengl/host/tools/emugen/ApiGen.cpp')
-rw-r--r-- | emulator/opengl/host/tools/emugen/ApiGen.cpp | 1232 |
1 files changed, 0 insertions, 1232 deletions
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp deleted file mode 100644 index 8be0270..0000000 --- a/emulator/opengl/host/tools/emugen/ApiGen.cpp +++ /dev/null @@ -1,1232 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "ApiGen.h" -#include "EntryPoint.h" -#include <stdio.h> -#include <stdlib.h> -#include "strUtils.h" -#include <errno.h> -#include <sys/types.h> - -/* Define this to 1 to enable support for the 'isLarge' variable flag - * that instructs the encoder to send large data buffers by a direct - * write through the pipe (i.e. without copying it into a temporary - * buffer. This has definite performance benefits when using a QEMU Pipe. - * - * Set to 0 otherwise. - */ -#define WITH_LARGE_SUPPORT 1 - -// Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned. -// This prevents crashes with certain backends (e.g. OSMesa). -#define USE_ALIGNED_BUFFERS 1 - -EntryPoint * ApiGen::findEntryByName(const std::string & name) -{ - EntryPoint * entry = NULL; - - size_t n = this->size(); - for (size_t i = 0; i < n; i++) { - if (at(i).name() == name) { - entry = &(at(i)); - break; - } - } - return entry; -} - -void ApiGen::printHeader(FILE *fp) const -{ - fprintf(fp, "// Generated Code - DO NOT EDIT !!\n"); - fprintf(fp, "// generated by 'emugen'\n"); -} - -int ApiGen::genProcTypes(const std::string &filename, SideType side) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return -1; - } - printHeader(fp); - - const char* basename = m_basename.c_str(); - - fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side)); - fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side)); - fprintf(fp, "\n\n"); - fprintf(fp, "\n#include \"%s_types.h\"\n",basename); - fprintf(fp, "#ifndef %s_APIENTRY\n",basename); - fprintf(fp, "#define %s_APIENTRY \n",basename); - fprintf(fp, "#endif\n"); - - - for (size_t i = 0; i < size(); i++) { - EntryPoint *e = &at(i); - - fprintf(fp, "typedef "); - e->retval().printType(fp); - fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side)); - if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); } - if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); } - - VarsArray & evars = e->vars(); - size_t n = evars.size(); - - for (size_t j = 0; j < n; j++) { - if (!evars[j].isVoid()) { - if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", "); - evars[j].printType(fp); - } - } - fprintf(fp, ");\n"); - } - fprintf(fp, "\n\n#endif\n"); - return 0; -} - -int ApiGen::genFuncTable(const std::string &filename, SideType side) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return -1; - } - printHeader(fp); - - fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side)); - fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side)); - fprintf(fp, "\n\n"); - fprintf(fp, "static const struct _%s_funcs_by_name {\n", m_basename.c_str()); - fprintf(fp, - "\tconst char *name;\n" \ - "\tvoid *proc;\n" \ - "} %s_funcs_by_name[] = {\n", m_basename.c_str()); - - - for (size_t i = 0; i < size(); i++) { - EntryPoint *e = &at(i); - if (e->notApi()) continue; - fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str()); - } - fprintf(fp, "};\n"); - fprintf(fp, "static const int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n", - m_basename.c_str(), m_basename.c_str(), m_basename.c_str()); - fprintf(fp, "\n\n#endif\n"); - return 0; -} - - -int ApiGen::genContext(const std::string & filename, SideType side) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return -1; - } - printHeader(fp); - - fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side)); - fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side)); - - // fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str()); - fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", m_basename.c_str(), sideString(side)); - - StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders; - for (size_t i = 0; i < contextHeaders.size(); i++) { - fprintf(fp, "#include %s\n", contextHeaders[i].c_str()); - } - fprintf(fp, "\n"); - - fprintf(fp, "\nstruct %s_%s_context_t {\n\n", m_basename.c_str(), sideString(side)); - for (size_t i = 0; i < size(); i++) { - EntryPoint *e = &at(i); - fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str()); - } - - // virtual destructor - fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side)); - // accessor - if (side == CLIENT_SIDE || side == WRAPPER_SIDE) { - fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n", - m_basename.c_str(), sideString(side)); - fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n"); - } - - // init function - fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n"); - - //client site set error virtual func - if (side == CLIENT_SIDE) { - fprintf(fp, "\tvirtual void setError(unsigned int error){ (void)error; };\n"); - fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n"); - } - - fprintf(fp, "};\n"); - - fprintf(fp, "\n#endif\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; -} - - -int ApiGen::genOpcodes(const std::string &filename) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return errno; - } - - printHeader(fp); - fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str()); - fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str()); - for (size_t i = 0; i < size(); i++) { - fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode); - } - fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode); - fprintf(fp,"\n\n#endif\n"); - fclose(fp); - return 0; - -} -int ApiGen::genAttributesTemplate(const std::string &filename ) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return -1; - } - - for (size_t i = 0; i < size(); i++) { - if (at(i).hasPointers()) { - fprintf(fp, "#"); - at(i).print(fp); - fprintf(fp, "%s\n\n", at(i).name().c_str()); - } - } - fclose(fp); - return 0; -} - -int ApiGen::genEncoderHeader(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 + "_encoder_context_t"; - - fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str()); - fprintf(fp, "#define GUARD_%s\n\n", classname.c_str()); - - fprintf(fp, "#include \"IOStream.h\"\n"); - fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE)); - - for (size_t i = 0; i < m_encoderHeaders.size(); i++) { - fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str()); - } - fprintf(fp, "\n"); - - fprintf(fp, "struct %s : public %s_%s_context_t {\n\n", - classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE)); - fprintf(fp, "\tIOStream *m_stream;\n\n"); - - fprintf(fp, "\t%s(IOStream *stream);\n", classname.c_str()); - fprintf(fp, "};\n\n"); - - fprintf(fp, "#endif // GUARD_%s", classname.c_str()); - - fclose(fp); - return 0; -} - -// Format the byte length expression for a given variable into a user-provided buffer -// If the variable type is not a pointer, this is simply its size as a decimal constant -// If the variable is a pointer, this will be an expression provided by the .attrib file -// through the 'len' attribute. -// -// Returns 1 if the variable is a pointer, 0 otherwise -// -static int getVarEncodingSizeExpression(Var& var, EntryPoint* e, char* buff, size_t bufflen) -{ - int ret = 0; - if (!var.isPointer()) { - snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes()); - } else { - ret = 1; - const char* lenExpr = var.lenExpression().c_str(); - const char* varname = var.name().c_str(); - if (e != NULL && lenExpr[0] == '\0') { - fprintf(stderr, "%s: data len is undefined for '%s'\n", - e->name().c_str(), varname); - } - if (var.nullAllowed()) { - snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr); - } else { - snprintf(buff, bufflen, "%s", lenExpr); - } - } - return ret; -} - -static int writeVarEncodingSize(Var& var, FILE* fp) -{ - int ret = 0; - if (!var.isPointer()) { - fprintf(fp, "%u", (unsigned int) var.type()->bytes()); - } else { - ret = 1; - fprintf(fp, "__size_%s", var.name().c_str()); - } - return ret; -} - - - -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()); - } - } -} - -#if WITH_LARGE_SUPPORT -static void writeVarLargeEncodingExpression(Var& var, FILE* fp) -{ - const char* varname = var.name().c_str(); - - fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname); - if (var.nullAllowed()) { - fprintf(fp, "\tif (%s != NULL) ", varname); - } else { - fprintf(fp, "\t"); - } - if (var.writeExpression() != "") { - fprintf(fp, "%s", var.writeExpression().c_str()); - } else { - fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname); - } - fprintf(fp, ";\n"); -} -#endif /* WITH_LARGE_SUPPORT */ - -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::genDecoderHeader(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"; - - fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str()); - fprintf(fp, "#define GUARD_%s\n\n", classname.c_str()); - - fprintf(fp, "#include \"IOStream.h\" \n"); - fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE)); - - for (size_t i = 0; i < m_decoderHeaders.size(); i++) { - fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str()); - } - fprintf(fp, "\n"); - - fprintf(fp, "struct %s : public %s_%s_context_t {\n\n", - classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE)); - fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n"); - fprintf(fp, "\n};\n\n"); - fprintf(fp, "#endif // GUARD_%s\n", classname.c_str()); - - fclose(fp); - return 0; -} - -int ApiGen::genContextImpl(const std::string &filename, SideType side) -{ - FILE *fp = fopen(filename.c_str(), "wt"); - if (fp == NULL) { - perror(filename.c_str()); - return -1; - } - printHeader(fp); - - std::string classname = m_basename + "_" + sideString(side) + "_context_t"; - size_t n = size(); - fprintf(fp, "\n\n#include <string.h>\n"); - fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side)); - fprintf(fp, "#include <stdio.h>\n\n"); - - // init function; - fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str()); - for (size_t i = 0; i < n; i++) { - EntryPoint *e = &at(i); - fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n", - e->name().c_str(), - e->name().c_str(), - sideString(side), - e->name().c_str()); - } - fprintf(fp, "\treturn 0;\n"); - fprintf(fp, "}\n\n"); - fclose(fp); - return 0; -} - -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"; - } - } - - if (pass == PASS_FunctionCall || - pass == PASS_DebugPrint) { - fprintf(fp, ");\n"); - } - - if (pass == PASS_TmpBuffAlloc) { - if (!e->retval().isVoid() && !e->retval().isPointer()) { - if (!totalTmpBuffExist) - fprintf(fp, - "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", - retvalType.c_str()); - else - fprintf(fp, - "\t\t\ttotalTmpSize += sizeof(%s);\n", - retvalType.c_str()); - - totalTmpBuffExist = true; - } - if (totalTmpBuffExist) { - fprintf(fp, - "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n"); - } - } - - if (pass == PASS_Epilog) { - // send back out pointers data as well as retval - if (totalTmpBuffExist) { - fprintf(fp, "\t\t\tstream->flush();\n"); - } - } - - } // pass; - fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str()); - fprintf(fp, "\t\t\tbreak;\n"); - fprintf(fp, "\t\t}\n"); - - delete [] tmpBufOffset; - } - fprintf(fp, "\t\t\tdefault:\n"); - fprintf(fp, "\t\t\t\tunknownOpcode = true;\n"); - fprintf(fp, "\t\t} //switch\n"); - if (strstr(m_basename.c_str(), "gl")) { - fprintf(fp, "#ifdef CHECK_GL_ERROR\n"); - fprintf(fp, "\tint err = lastCall[0] ? this->glGetError() : GL_NO_ERROR;\n"); - fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str()); - fprintf(fp, "#endif\n"); - } - - fprintf(fp, "\t\tif (!unknownOpcode) {\n"); - fprintf(fp, "\t\t\tpos += packetLen;\n"); - fprintf(fp, "\t\t\tptr += packetLen;\n"); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t} // while\n"); - fprintf(fp, "\treturn pos;\n"); - fprintf(fp, "}\n"); - - fclose(fp); - return 0; -} - -int ApiGen::readSpec(const std::string & filename) -{ - FILE *specfp = fopen(filename.c_str(), "rt"); - if (specfp == NULL) { - return -1; - } - - char line[1000]; - unsigned int lc = 0; - while (fgets(line, sizeof(line), specfp) != NULL) { - lc++; - EntryPoint ref; - if (ref.parse(lc, std::string(line))) { - push_back(ref); - updateMaxEntryPointsParams(ref.vars().size()); - } - } - fclose(specfp); - return 0; -} - -int ApiGen::readAttributes(const std::string & attribFilename) -{ - enum { ST_NAME, ST_ATT } state; - - FILE *fp = fopen(attribFilename.c_str(), "rt"); - if (fp == NULL) { - perror(attribFilename.c_str()); - return -1; - } - char buf[1000]; - - state = ST_NAME; - EntryPoint *currentEntry = NULL; - size_t lc = 0; - bool globalAttributes = false; - while (fgets(buf, sizeof(buf), fp) != NULL) { - lc++; - std::string line(buf); - if (line.size() == 0) continue; // could that happen? - - if (line.at(0) == '#') continue; // comment - - size_t first = line.find_first_not_of(" \t\n"); - if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME; - - line = trim(line); - if (line.size() == 0 || line.at(0) == '#') continue; - - switch(state) { - case ST_NAME: - if (line == "GLOBAL") { - globalAttributes = true; - } else { - globalAttributes = false; - currentEntry = findEntryByName(line); - if (currentEntry == NULL) { - fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str()); - } - } - state = ST_ATT; - break; - case ST_ATT: - if (globalAttributes) { - setGlobalAttribute(line, lc); - } else if (currentEntry != NULL) { - currentEntry->setAttribute(line, lc); - } - break; - } - } - return 0; -} - - -int ApiGen::setGlobalAttribute(const std::string & line, size_t lc) -{ - size_t pos = 0; - size_t last; - std::string token = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - - if (token == "base_opcode") { - std::string str = getNextToken(line, pos, &last, WHITESPACE); - if (str.size() == 0) { - fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc); - } else { - setBaseOpcode(atoi(str.c_str())); - } - } else if (token == "encoder_headers") { - std::string str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - while (str.size() != 0) { - encoderHeaders().push_back(str); - str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - } - } else if (token == "client_context_headers") { - std::string str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - while (str.size() != 0) { - clientContextHeaders().push_back(str); - str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - } - } else if (token == "server_context_headers") { - std::string str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - while (str.size() != 0) { - serverContextHeaders().push_back(str); - str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - } - } else if (token == "decoder_headers") { - std::string str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - while (str.size() != 0) { - decoderHeaders().push_back(str); - str = getNextToken(line, pos, &last, WHITESPACE); - pos = last; - } - } - else { - fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str()); - } - - return 0; -} - |