Convert ApiGen.cpp to unix file format

Change-Id: I1a9bd2f47991963a890eff5e73f795196ccd83f8
diff --git a/protocols/generic-apigen/ApiGen.cpp b/protocols/generic-apigen/ApiGen.cpp
index 906ac49..1238512 100644
--- a/protocols/generic-apigen/ApiGen.cpp
+++ b/protocols/generic-apigen/ApiGen.cpp
@@ -1,1593 +1,1593 @@
-/*

-* 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 "base/EnumFlags.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

-

-// Set these to 1 if you want to instrument either guest's or host's code for

-// time-per-call printing.

-#define INSTRUMENT_TIMING_GUEST 0

-#define INSTRUMENT_TIMING_HOST 0

-

-// Set to 1 to print to logcat for every GL call encoded.

-#define DLOG_ALL_ENCODES 0

-

-// Set to 1 to check GL errors before and after every decoder call.

-#define DECODER_CHECK_GL_ERRORS 0

-

-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, "#ifdef _MSC_VER\n");

-    fprintf(fp, "#include <stdint.h>\n");

-    fprintf(fp, "#endif\n");

-    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");

-

-        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {

-            fprintf(fp, "typedef ");

-            e->retval().printType(fp);

-            fprintf(fp, " (%s_APIENTRY *%s_dec_%s_proc_t) (", basename, e->name().c_str(), sideString(side));

-

-            VarsArray & evars = e->vars();

-            size_t n = evars.size();

-

-            for (size_t j = 0; j < n; j++) {

-                if (!evars[j].isVoid()) {

-                    if (j != 0) 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_%s_proc.h\"\n",

-            m_basename.c_str(),

-            side == CLIENT_SIDE ? "client" : "server");

-    fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());

-

-    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));

-

-    // API entry points

-    for (size_t i = 0; i < size(); i++) {

-        EntryPoint *e = &at(i);

-        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {

-            fprintf(fp, "\t%s_dec_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());

-            fprintf(fp, "\t%s_%s_proc_t %s_dec;\n", e->name().c_str(), sideString(side), e->name().c_str());

-        } else {

-            fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());

-        }

-    }

-

-    // virtual destructor

-    fprintf(fp, "\tvirtual ~%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, "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, "#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 \"ChecksumCalculator.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");

-    fprintf(fp, "\tChecksumCalculator *m_checksumCalculator;\n\n");

-

-    fprintf(fp, "\t%s(IOStream *stream, ChecksumCalculator *checksumCalculator);\n", classname.c_str());

-    fprintf(fp, "\tvirtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }\n");

-    fprintf(fp, "};\n\n");

-

-    fprintf(fp, "#endif  // GUARD_%s\n", 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

-//

-enum class EncodingSizeFlags {

-    None = 0,

-    DmaPtrOnly = 1,

-    ExcludeOut = 2,

-    UseExistingVar = 4,

-};

-

-static int getVarEncodingSizeExpression(

-        Var& var, EntryPoint* e, char* buff, size_t bufflen,

-        EncodingSizeFlags flags)

-{

-    if (!var.isPointer()) {

-        snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());

-        return 0;

-    }

-

-    if ((flags & EncodingSizeFlags::DmaPtrOnly) != 0) {

-        snprintf(buff, bufflen, "8");

-    } else if ((flags & EncodingSizeFlags::ExcludeOut) != 0 &&

-            !(var.pointerDir() & Var::POINTER_IN)) {

-        snprintf(buff, bufflen, "0");

-    } else if ((flags & EncodingSizeFlags::UseExistingVar) != 0) {

-        snprintf(buff, bufflen, "__size_%s", var.name().c_str());

-    } else {

-        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 1;

-}

-

-static int writeVarEncodingSize(Var& var, bool excludeOutVars, FILE* fp)

-{

-    int ret = 0;

-    if (!var.isPointer()) {

-        fprintf(fp, "%u", (unsigned int) var.type()->bytes());

-    } else {

-        ret = 1;

-        if (var.isDMA()) {

-            fprintf(fp, "8");

-            return ret;

-        }

-

-        if (excludeOutVars && !(var.pointerDir() & Var::POINTER_IN)) {

-            fprintf(fp, "0");

-        } else {

-            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

-        if (var.isDMA()) {

-            fprintf(fp, "\t*(uint64_t *)(ptr) = ctx->lockAndWriteDma(%s, __size_%s); ptr += 8;\n", varname, varname);

-        } else {

-            fprintf(fp, "\tmemcpy(ptr, &__size_%s, 4); 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);

-    fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname);

-    if (var.nullAllowed()) {

-        fprintf(fp, "\tif (%s != NULL) {\n", varname);

-    }

-    if (var.writeExpression() != "") {

-        fprintf(fp, "%s", var.writeExpression().c_str());

-    } else {

-        if (var.guestPackExpression() != "") {

-            fprintf(fp, "\t\t%s;\n", var.guestPackExpression().c_str());

-        } else {

-            fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname);

-        }

-        fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname);

-    }

-    if (var.nullAllowed()) fprintf(fp, "\t}\n");

-}

-#endif /* WITH_LARGE_SUPPORT */

-

-static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) {

-    fprintf(fp, "\tif (useChecksum) {\n"

-                "\t\tunsigned char *checksumBufPtr = NULL;\n"

-                "\t\tunsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];\n"

-                "\t\tif (checksumSize > 0) checksumBufPtr = &checksumBuf[0];\n"

-                "\t\tstream->readback(checksumBufPtr, checksumSize);\n"

-                "\t\tif (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {\n"

-                "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n"

-                "\t\t\tabort();\n"

-                "\t\t}\n"

-                "\t}\n",

-            funcName

-    );

-}

-

-static void addGuestTimePrinting(const EntryPoint* e, bool hasTimeBeforeReadback,

-                                 FILE* fp) {

-#if INSTRUMENT_TIMING_GUEST

-    fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts1);\n");

-    fprintf(fp, "\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");

-    if (hasTimeBeforeReadback) {

-        fprintf(fp, "\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");

-        fprintf(fp, "\tALOGW(\"%s: %%ld (%%ld) us\\n\", timeDiff, timeDiff2);\n", e->name().c_str());

-    } else {

-        fprintf(fp, "\tALOGW(\"%s: %%ld us\\n\", timeDiff);\n", e->name().c_str());

-    }

-#endif

-}

-

-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");

-    fprintf(fp, "#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 <vector>\n\n");

-    fprintf(fp, "#include <stdio.h>\n\n");

-    fprintf(fp, "#include \"android/base/Tracing.h\"\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");

-#if DLOG_ALL_ENCODES

-        fprintf(fp, "ALOGD(\"%%s: enter\", __FUNCTION__);\n");

-#endif

-

-        fprintf(fp, "\tAEMU_SCOPED_TRACE(\"%s encode\");\n", e->name().c_str());

-

-#if INSTRUMENT_TIMING_GUEST

-        fprintf(fp, "\tstruct timespec ts0, ts1;\n");

-        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts0);\n");

-#endif

-

-//      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"

-                    "\tChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n"

-                    "\tbool useChecksum = checksumCalculator->getVersion() > 0;\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),

-                                         EncodingSizeFlags::None);

-            fprintf(fp, "%s;\n", buff);

-        }

-

-        bool hasLargeFields = false;

-#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 (without checksum)

-        fprintf(fp, "\t unsigned char *ptr;\n");

-        fprintf(fp, "\t unsigned char *buf;\n");

-        fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");

-

-        for (j = 0; j < maxvars; j++) {

-            fprintf(fp, " + ");

-            npointers += writeVarEncodingSize(evars[j], true, fp);

-        }

-        if (npointers > 0) {

-            fprintf(fp, " + %zu*4", npointers);

-        }

-        fprintf(fp, ";\n");

-

-        // Then, size of the checksum string

-        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");

-

-        // And, size of the whole thing

-        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\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+checksum_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, "\tbuf = stream->alloc(totalSize);\n");

-

-                } else {

-                    hasLargeFields = true;

-                    // allocate buffer from the stream until the first large variable

-                    fprintf(fp, "\tbuf = 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], false, fp);

-                        }

-                        if (npointers > 0) {

-                            fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";

-                        }

-                    }

-                    fprintf(fp,");\n");

-                }

-                fprintf(fp, "\tptr = buf;\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, &totalSize, 4);  ptr += 4;\n\n");

-                }

-

-                if (maxvars == 0) {

-                    fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");

-                    break;

-                }

-

-                // encode non-large fields in this fragment

-                for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {

-                    writeVarEncodingExpression(evars[j],fp);

-                }

-

-                fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");

-                // 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, "\tunsigned char *ptr;\n");

-        fprintf(fp, "\tunsigned char *buf;\n");

-        fprintf(fp, "\tconst size_t sizeWithoutChecksum = 8");

-        for (size_t j = 0; j < nvars; j++) {

-            npointers += getVarEncodingSizeExpression(

-                    evars[j], e, buff, sizeof(buff),

-                    (evars[j].isDMA() ? EncodingSizeFlags::DmaPtrOnly

-                                      : EncodingSizeFlags::None) |

-                            EncodingSizeFlags::UseExistingVar |

-                            EncodingSizeFlags::ExcludeOut);

-            fprintf(fp, " + %s", buff);

-        }

-        fprintf(fp, " + %u * 4;\n", (unsigned int)npointers);

-        // Size of checksum

-        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");

-        // Size of the whole thing

-        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");

-

-        // allocate buffer from the stream;

-        fprintf(fp, "\tptr = buf = stream->alloc(totalSize);\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, &totalSize, 4);  ptr += 4;\n\n");

-

-        // out variables

-        for (size_t j = 0; j < nvars; j++) {

-            writeVarEncodingExpression(evars[j], fp);

-        }

-

-        fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr - buf);\n");

-#endif /* !WITH_LARGE_SUPPORT */

-

-        // checksum

-        if (hasLargeFields) {

-            fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n");

-            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n");

-        } else {

-            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n");

-        }

-

-        // in variables;

-        bool hasTimeBeforeReadback = false;

-        bool hasReadbackChecksum = false;

-        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();

-                    const char* indent = "\t";

-

-#if INSTRUMENT_TIMING_GUEST

-                    if (!hasTimeBeforeReadback) {

-                        hasTimeBeforeReadback = true;

-                        // Let's flush the stream before measuring the time.

-                        fprintf(fp, "\tstream->flush();\n");

-                        fprintf(fp, "\tstruct timespec ts2;\n");

-                        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");

-                    }

-#endif

-                    if (evars[j].nullAllowed()) {

-                        fprintf(fp, "\tif (%s != NULL) {\n",varname);

-                        indent = "\t\t";

-                    }

-

-                    if (evars[j].guestUnpackExpression() != "") {

-                        fprintf(fp, "%s%s;\n", indent, evars[j].guestUnpackExpression().c_str());

-                    } else {

-                        fprintf(fp, "%sstream->readback(%s, __size_%s);\n",

-                                indent, varname, varname);

-                    }

-                    fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n",

-                            indent, varname, varname);

-                    if (evars[j].nullAllowed()) {

-                        fprintf(fp, "\t}\n");

-                    }

-                    hasReadbackChecksum = true;

-                }

-            }

-        }

-//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");

-            }

-            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);

-            fprintf(fp, "\t return NULL;\n");

-        } else if (e->retval().type()->name() != "void") {

-#if INSTRUMENT_TIMING_GUEST

-            if (!hasTimeBeforeReadback) {

-                hasTimeBeforeReadback = true;

-                fprintf(fp, "\tstream->flush();\n");

-                fprintf(fp, "\tstruct timespec ts2;\n");

-                fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");

-            }

-#endif

-

-            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, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n",

-                    (unsigned) e->retval().type()->bytes());

-            writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);

-            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);

-            fprintf(fp, "\treturn retval;\n");

-        } else {

-            if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n");

-            if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);

-            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);

-        }

-        fprintf(fp, "}\n\n");

-    }

-

-    fprintf(fp, "}  // namespace\n\n");

-

-    // constructor

-    fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str());

-    fprintf(fp, "\tm_stream = stream;\n");

-    fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\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 \"ChecksumCalculator.h\"\n");

-    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));

-#if INSTRUMENT_TIMING_HOST

-    fprintf(fp, "#include \"time.h\"\n");

-#endif

-

-    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, ChecksumCalculator* checksumCalc);\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");

-

-    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);

-        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {

-            fprintf(fp, "\t%s = (%s_dec_%s_proc_t) getProc(\"%s\", userData);\n",

-                    e->name().c_str(),

-                    e->name().c_str(),

-                    sideString(side),

-                    e->name().c_str());

-        } else {

-            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();

-

-    bool changesChecksum = false;

-    for (size_t i = 0; i < size(); ++i) {

-        const EntryPoint& ep = at(i);

-        if (ep.name().find("SelectChecksum") != std::string::npos) {

-            changesChecksum = true;

-            break;

-        }

-    }

-

-    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 \"ChecksumCalculatorThreadInfo.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");

-

-    fprintf(fp,

-#if DECODER_CHECK_GL_ERRORS

-            "#define CHECK_GL_ERRORS\n"

-#endif

-            "#ifdef CHECK_GL_ERRORS\n"

-            "#  define SET_LASTCALL(name)  sprintf(lastCall, #name)\n"

-            "#else\n"

-            "#  define SET_LASTCALL(name)\n"

-            "#endif\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, ChecksumCalculator* checksumCalc) {\n", classname.c_str());

-    fprintf(fp,

-"\tif (len < 8) return 0; \n\

-#ifdef CHECK_GL_ERRORS\n\

-\tchar lastCall[256] = {0};\n\

-#endif\n\

-\tunsigned char *ptr = (unsigned char *)buf;\n\

-\tconst unsigned char* const end = (const unsigned char*)buf + len;\n");

-    if (!changesChecksum) {

-        fprintf(fp,

-R"(    const size_t checksumSize = checksumCalc->checksumByteSize();

-    const bool useChecksum = checksumSize > 0;

-)");

-    }

-    fprintf(fp,

-"\twhile (end - ptr >= 8) {\n\

-\t\tuint32_t opcode = *(uint32_t *)ptr;   \n\

-\t\tint32_t packetLen = *(int32_t *)(ptr + 4);\n\

-\t\tif (end - ptr < packetLen) return ptr - (unsigned char*)buf;\n");

-    if (changesChecksum) {

-        fprintf(fp,

-R"(        // Do this on every iteration, as some commands may change the checksum

-        // calculation parameters.

-        const size_t checksumSize = checksumCalc->checksumByteSize();

-        const bool useChecksum = checksumSize > 0;

-)");

-    }

-    fprintf(fp, "\t\tswitch(opcode) {\n");

-

-    for (size_t f = 0; f < n; f++) {

-        enum Pass_t {

-            PASS_FIRST = 0,

-            PASS_VariableDeclarations = PASS_FIRST,

-            PASS_Protocol,

-            PASS_TmpBuffAlloc,

-            PASS_MemAlloc,

-            PASS_DebugPrint,

-            PASS_FunctionCall,

-            PASS_FlushOutput,

-            PASS_Epilog,

-            PASS_LAST };

-        EntryPoint *e = &(*this)[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()) + " ";

-        }

-

-        // TODO - add for return value;

-        fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());

-        fprintf(fp, "\t\t\tandroid::base::beginTrace(\"%s decode\");\n", e->name().c_str());

-

-#if INSTRUMENT_TIMING_HOST

-        fprintf(fp, "\t\t\tstruct timespec ts0, ts1, ts2;\n");

-        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts0);\n");

-#endif

-        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();

-        }

-

-#define SKIP_DEBUG_PRINT 1

-

-        for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) {

-#if SKIP_DEBUG_PRINT

-            if (pass == PASS_DebugPrint) continue;

-#endif

-

-#if INSTRUMENT_TIMING_HOST

-            if (pass == PASS_FunctionCall) {

-                fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts2);\n");

-            }

-#endif

-            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) {

-                if (e->customDecoder() && !e->notApi()) {

-                    fprintf(fp, "\t\t\tthis->%s_dec(", e->hostApiName().c_str());

-                } else {

-                    fprintf(fp, "\t\t\tthis->%s(", e->hostApiName().c_str());

-                }

-                if (e->customDecoder()) {

-                    fprintf(fp, "this"); // add a context to the call

-                }

-            } else if (pass == PASS_DebugPrint) {

-                if (strstr(m_basename.c_str(), "gl")) {

-                    fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");

-                    fprintf(fp, "\t\tGLint err = this->glGetError();\n");

-                    fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (pre-call): 0x%%X before %s\\n\", err);\n",

-                            m_basename.c_str(), e->name().c_str());

-                    fprintf(fp, "\t\t#endif\n");

-                }

-                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() && v->isDMA()) {

-                    if (pass == PASS_VariableDeclarations) {

-                        fprintf(fp,

-                                "\t\t\tuint64_t var_%s_guest_paddr = Unpack<uint64_t,uint64_t>(ptr + %s);\n"

-                                "\t\t\t%s var_%s = stream->getDmaForReading(var_%s_guest_paddr);\n",

-                                var_name,

-                                varoffset.c_str(),

-                                var_type_name,

-                                var_name,

-                                var_name);

-                    }

-                    if (pass == PASS_FunctionCall ||

-                        pass == PASS_DebugPrint) {

-                        fprintf(fp, "var_%s", var_name);

-                    }

-                    varoffset += " + 8";

-                }

-

-                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->isDMA()) {

-                    if (v->pointerDir() & Var::POINTER_IN) {

-                        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 (v->unpackExpression().size() > 0) {

-                                fprintf(fp,

-                                    "\t\t\tvoid* inptr_%s_unpacked;\n"

-                                    "\t\t\t%s;\n",

-                                    var_name,

-                                    v->unpackExpression().c_str());

-                            }

-

-                        }

-                        if (pass == PASS_FunctionCall &&

-                            v->pointerDir() == Var::POINTER_IN) {

-                            if (v->nullAllowed()) {

-                                fprintf(fp,

-                                        "size_%s == 0 ? nullptr : (%s)(inptr_%s.get())",

-                                        var_name,

-                                        var_type_name,

-                                        var_name);

-                            } else {

-                                if (v->unpackExpression().size() > 0) {

-                                    fprintf(fp,

-                                            "(%s)(inptr_%s_unpacked)",

-                                            var_type_name,

-                                            var_name);

-                                } else {

-                                    fprintf(fp,

-                                            "(%s)(inptr_%s.get())",

-                                            var_type_name,

-                                            var_name);

-                                }

-                            }

-                        } else if (pass == PASS_DebugPrint &&

-                                   v->pointerDir() == Var::POINTER_IN) {

-                            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 &&

-                            v->pointerDir() == Var::POINTER_IN) {

-                            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 &&

-                                   v->pointerDir() == Var::POINTER_IN) {

-                            fprintf(fp,

-                                    "(%s)(inptr_%s), size_%s",

-                                    var_type_name,

-                                    var_name,

-                                    var_name);

-                        }

-    #endif  // !USE_ALIGNED_BUFFERS

-                        varoffset += " + 4 + size_";

-                        varoffset += var_name;

-                    }

-                    if (v->pointerDir() & Var::POINTER_OUT)  { // 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);

-                            // If both input and output variable, initialize with the input.

-                            if (v->pointerDir() == Var::POINTER_INOUT) {

-                                fprintf(fp,

-                                        "\t\t\tmemcpy(outptr_%s.get(), inptr_%s.get(), size_%s);\n",

-                                        var_name,

-                                        var_name,

-                                        var_name);

-                            }

-

-                            if (v->hostPackExpression() != "") {

-                                fprintf(fp, "\t\t\tvoid* forPacking_%s = nullptr;\n", var_name);

-                            }

-                            if (v->hostPackTmpAllocExpression() != "") {

-                                fprintf(fp, "\t\t\t%s;\n", v->hostPackTmpAllocExpression().c_str());

-                            }

-                        } else if (pass == PASS_FunctionCall) {

-                            if (v->hostPackExpression() != "") {

-                                fprintf(fp,

-                                        "(%s)(forPacking_%s)",

-                                        var_type_name,

-                                        var_name);

-                            } else {

-                                if (v->nullAllowed()) {

-                                    fprintf(fp,

-                                            "size_%s == 0 ? nullptr : (%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) {

-                            if (v->hostPackExpression() != "") {

-                                fprintf(fp,

-                                        "\t\t\tif (size_%s) {\n"

-                                        "\t\t\t%s; }\n",

-                                        var_name,

-                                        v->hostPackExpression().c_str());

-                            }

-                            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

-                    if (v->pointerDir() == Var::POINTER_OUT) {

-                        varoffset += " + 4";

-                    }

-                    }

-                }

-            }

-

-            if (pass == PASS_Protocol) {

-                fprintf(fp,

-                        "\t\t\tif (useChecksum) {\n"

-                        "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, %s, "

-                        "ptr + %s, checksumSize, "

-                        "\n\t\t\t\t\t\"%s::decode,"

-                        " OP_%s: GL checksumCalculator failure\\n\");\n"

-                        "\t\t\t}\n",

-                        varoffset.c_str(),

-                        varoffset.c_str(),

-                        classname.c_str(),

-                        e->name().c_str()

-                        );

-

-                varoffset += " + 4";

-            }

-

-            if (pass == PASS_FunctionCall ||

-                pass == PASS_DebugPrint) {

-                fprintf(fp, ");\n");

-

-                if (pass == PASS_FunctionCall) {

-                    // unlock all dma buffers that have been passed

-                    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();

-                        if (v->isDMA()) {

-                            fprintf(fp,

-                                    "\t\t\tstream->unlockDma(var_%s_guest_paddr);\n",

-                                    var_name);

-                        }

-                    }

-                }

-            }

-

-            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\ttotalTmpSize += checksumSize;\n"

-                            "\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\tif (useChecksum) {\n"

-                            "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, "

-                            "&tmpBuf[0], totalTmpSize - checksumSize, "

-                            "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n"

-                            "\t\t\t}\n"

-                            "\t\t\tstream->flush();\n");

-                }

-            }

-        } // pass;

-

-#if INSTRUMENT_TIMING_HOST

-        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts1);\n");

-        fprintf(fp, "\t\t\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");

-        fprintf(fp, "\t\t\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");

-        fprintf(fp, "\t\t\tprintf(\"(timing) %%4ld.%%06ld %s: %%ld (%%ld) us\\n\", "

-                    "ts1.tv_sec, ts1.tv_nsec/1000, timeDiff, timeDiff2);\n", e->name().c_str());

-#endif

-        fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());

-        fprintf(fp, "\t\t\tandroid::base::endTrace();\n");

-        fprintf(fp, "\t\t\tbreak;\n");

-        fprintf(fp, "\t\t}\n");

-

-        delete [] tmpBufOffset;

-    }

-    fprintf(fp, "\t\tdefault:\n");

-    fprintf(fp, "\t\t\treturn ptr - (unsigned char*)buf;\n");

-    fprintf(fp, "\t\t} //switch\n");

-    if (strstr(m_basename.c_str(), "gl")) {

-        fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");

-        fprintf(fp, "\t\tGLint err = this->glGetError();\n");

-        fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (post-call): 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());

-        fprintf(fp, "\t\t#endif\n");

-    }

-

-    fprintf(fp, "\t\tptr += packetLen;\n");

-    fprintf(fp, "\t} // while\n");

-    fprintf(fp, "\treturn ptr - (unsigned char*)buf;\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;

-}

+/*
+* 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 "base/EnumFlags.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
+
+// Set these to 1 if you want to instrument either guest's or host's code for
+// time-per-call printing.
+#define INSTRUMENT_TIMING_GUEST 0
+#define INSTRUMENT_TIMING_HOST 0
+
+// Set to 1 to print to logcat for every GL call encoded.
+#define DLOG_ALL_ENCODES 0
+
+// Set to 1 to check GL errors before and after every decoder call.
+#define DECODER_CHECK_GL_ERRORS 0
+
+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, "#ifdef _MSC_VER\n");
+    fprintf(fp, "#include <stdint.h>\n");
+    fprintf(fp, "#endif\n");
+    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");
+
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "typedef ");
+            e->retval().printType(fp);
+            fprintf(fp, " (%s_APIENTRY *%s_dec_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
+
+            VarsArray & evars = e->vars();
+            size_t n = evars.size();
+
+            for (size_t j = 0; j < n; j++) {
+                if (!evars[j].isVoid()) {
+                    if (j != 0) 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_%s_proc.h\"\n",
+            m_basename.c_str(),
+            side == CLIENT_SIDE ? "client" : "server");
+    fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+
+    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));
+
+    // API entry points
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "\t%s_dec_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+            fprintf(fp, "\t%s_%s_proc_t %s_dec;\n", e->name().c_str(), sideString(side), e->name().c_str());
+        } else {
+            fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+        }
+    }
+
+    // virtual destructor
+    fprintf(fp, "\tvirtual ~%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, "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, "#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 \"ChecksumCalculator.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");
+    fprintf(fp, "\tChecksumCalculator *m_checksumCalculator;\n\n");
+
+    fprintf(fp, "\t%s(IOStream *stream, ChecksumCalculator *checksumCalculator);\n", classname.c_str());
+    fprintf(fp, "\tvirtual uint64_t lockAndWriteDma(void*, uint32_t) { return 0; }\n");
+    fprintf(fp, "};\n\n");
+
+    fprintf(fp, "#endif  // GUARD_%s\n", 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
+//
+enum class EncodingSizeFlags {
+    None = 0,
+    DmaPtrOnly = 1,
+    ExcludeOut = 2,
+    UseExistingVar = 4,
+};
+
+static int getVarEncodingSizeExpression(
+        Var& var, EntryPoint* e, char* buff, size_t bufflen,
+        EncodingSizeFlags flags)
+{
+    if (!var.isPointer()) {
+        snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
+        return 0;
+    }
+
+    if ((flags & EncodingSizeFlags::DmaPtrOnly) != 0) {
+        snprintf(buff, bufflen, "8");
+    } else if ((flags & EncodingSizeFlags::ExcludeOut) != 0 &&
+            !(var.pointerDir() & Var::POINTER_IN)) {
+        snprintf(buff, bufflen, "0");
+    } else if ((flags & EncodingSizeFlags::UseExistingVar) != 0) {
+        snprintf(buff, bufflen, "__size_%s", var.name().c_str());
+    } else {
+        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 1;
+}
+
+static int writeVarEncodingSize(Var& var, bool excludeOutVars, FILE* fp)
+{
+    int ret = 0;
+    if (!var.isPointer()) {
+        fprintf(fp, "%u", (unsigned int) var.type()->bytes());
+    } else {
+        ret = 1;
+        if (var.isDMA()) {
+            fprintf(fp, "8");
+            return ret;
+        }
+
+        if (excludeOutVars && !(var.pointerDir() & Var::POINTER_IN)) {
+            fprintf(fp, "0");
+        } else {
+            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
+        if (var.isDMA()) {
+            fprintf(fp, "\t*(uint64_t *)(ptr) = ctx->lockAndWriteDma(%s, __size_%s); ptr += 8;\n", varname, varname);
+        } else {
+            fprintf(fp, "\tmemcpy(ptr, &__size_%s, 4); 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);
+    fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname);
+    if (var.nullAllowed()) {
+        fprintf(fp, "\tif (%s != NULL) {\n", varname);
+    }
+    if (var.writeExpression() != "") {
+        fprintf(fp, "%s", var.writeExpression().c_str());
+    } else {
+        if (var.guestPackExpression() != "") {
+            fprintf(fp, "\t\t%s;\n", var.guestPackExpression().c_str());
+        } else {
+            fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname);
+        }
+        fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname);
+    }
+    if (var.nullAllowed()) fprintf(fp, "\t}\n");
+}
+#endif /* WITH_LARGE_SUPPORT */
+
+static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) {
+    fprintf(fp, "\tif (useChecksum) {\n"
+                "\t\tunsigned char *checksumBufPtr = NULL;\n"
+                "\t\tunsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];\n"
+                "\t\tif (checksumSize > 0) checksumBufPtr = &checksumBuf[0];\n"
+                "\t\tstream->readback(checksumBufPtr, checksumSize);\n"
+                "\t\tif (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {\n"
+                "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n"
+                "\t\t\tabort();\n"
+                "\t\t}\n"
+                "\t}\n",
+            funcName
+    );
+}
+
+static void addGuestTimePrinting(const EntryPoint* e, bool hasTimeBeforeReadback,
+                                 FILE* fp) {
+#if INSTRUMENT_TIMING_GUEST
+    fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
+    fprintf(fp, "\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
+    if (hasTimeBeforeReadback) {
+        fprintf(fp, "\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
+        fprintf(fp, "\tALOGW(\"%s: %%ld (%%ld) us\\n\", timeDiff, timeDiff2);\n", e->name().c_str());
+    } else {
+        fprintf(fp, "\tALOGW(\"%s: %%ld us\\n\", timeDiff);\n", e->name().c_str());
+    }
+#endif
+}
+
+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");
+    fprintf(fp, "#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 <vector>\n\n");
+    fprintf(fp, "#include <stdio.h>\n\n");
+    fprintf(fp, "#include \"android/base/Tracing.h\"\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");
+#if DLOG_ALL_ENCODES
+        fprintf(fp, "ALOGD(\"%%s: enter\", __FUNCTION__);\n");
+#endif
+
+        fprintf(fp, "\tAEMU_SCOPED_TRACE(\"%s encode\");\n", e->name().c_str());
+
+#if INSTRUMENT_TIMING_GUEST
+        fprintf(fp, "\tstruct timespec ts0, ts1;\n");
+        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
+#endif
+
+//      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"
+                    "\tChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n"
+                    "\tbool useChecksum = checksumCalculator->getVersion() > 0;\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),
+                                         EncodingSizeFlags::None);
+            fprintf(fp, "%s;\n", buff);
+        }
+
+        bool hasLargeFields = false;
+#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 (without checksum)
+        fprintf(fp, "\t unsigned char *ptr;\n");
+        fprintf(fp, "\t unsigned char *buf;\n");
+        fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");
+
+        for (j = 0; j < maxvars; j++) {
+            fprintf(fp, " + ");
+            npointers += writeVarEncodingSize(evars[j], true, fp);
+        }
+        if (npointers > 0) {
+            fprintf(fp, " + %zu*4", npointers);
+        }
+        fprintf(fp, ";\n");
+
+        // Then, size of the checksum string
+        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
+
+        // And, size of the whole thing
+        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\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+checksum_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, "\tbuf = stream->alloc(totalSize);\n");
+
+                } else {
+                    hasLargeFields = true;
+                    // allocate buffer from the stream until the first large variable
+                    fprintf(fp, "\tbuf = 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], false, fp);
+                        }
+                        if (npointers > 0) {
+                            fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
+                        }
+                    }
+                    fprintf(fp,");\n");
+                }
+                fprintf(fp, "\tptr = buf;\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, &totalSize, 4);  ptr += 4;\n\n");
+                }
+
+                if (maxvars == 0) {
+                    fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
+                    break;
+                }
+
+                // encode non-large fields in this fragment
+                for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+                    writeVarEncodingExpression(evars[j],fp);
+                }
+
+                fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
+                // 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, "\tunsigned char *ptr;\n");
+        fprintf(fp, "\tunsigned char *buf;\n");
+        fprintf(fp, "\tconst size_t sizeWithoutChecksum = 8");
+        for (size_t j = 0; j < nvars; j++) {
+            npointers += getVarEncodingSizeExpression(
+                    evars[j], e, buff, sizeof(buff),
+                    (evars[j].isDMA() ? EncodingSizeFlags::DmaPtrOnly
+                                      : EncodingSizeFlags::None) |
+                            EncodingSizeFlags::UseExistingVar |
+                            EncodingSizeFlags::ExcludeOut);
+            fprintf(fp, " + %s", buff);
+        }
+        fprintf(fp, " + %u * 4;\n", (unsigned int)npointers);
+        // Size of checksum
+        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
+        // Size of the whole thing
+        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
+
+        // allocate buffer from the stream;
+        fprintf(fp, "\tptr = buf = stream->alloc(totalSize);\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, &totalSize, 4);  ptr += 4;\n\n");
+
+        // out variables
+        for (size_t j = 0; j < nvars; j++) {
+            writeVarEncodingExpression(evars[j], fp);
+        }
+
+        fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr - buf);\n");
+#endif /* !WITH_LARGE_SUPPORT */
+
+        // checksum
+        if (hasLargeFields) {
+            fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n");
+            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n");
+        } else {
+            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n");
+        }
+
+        // in variables;
+        bool hasTimeBeforeReadback = false;
+        bool hasReadbackChecksum = false;
+        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();
+                    const char* indent = "\t";
+
+#if INSTRUMENT_TIMING_GUEST
+                    if (!hasTimeBeforeReadback) {
+                        hasTimeBeforeReadback = true;
+                        // Let's flush the stream before measuring the time.
+                        fprintf(fp, "\tstream->flush();\n");
+                        fprintf(fp, "\tstruct timespec ts2;\n");
+                        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+                    }
+#endif
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\tif (%s != NULL) {\n",varname);
+                        indent = "\t\t";
+                    }
+
+                    if (evars[j].guestUnpackExpression() != "") {
+                        fprintf(fp, "%s%s;\n", indent, evars[j].guestUnpackExpression().c_str());
+                    } else {
+                        fprintf(fp, "%sstream->readback(%s, __size_%s);\n",
+                                indent, varname, varname);
+                    }
+                    fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n",
+                            indent, varname, varname);
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\t}\n");
+                    }
+                    hasReadbackChecksum = true;
+                }
+            }
+        }
+//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");
+            }
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+            fprintf(fp, "\t return NULL;\n");
+        } else if (e->retval().type()->name() != "void") {
+#if INSTRUMENT_TIMING_GUEST
+            if (!hasTimeBeforeReadback) {
+                hasTimeBeforeReadback = true;
+                fprintf(fp, "\tstream->flush();\n");
+                fprintf(fp, "\tstruct timespec ts2;\n");
+                fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+            }
+#endif
+
+            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, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n",
+                    (unsigned) e->retval().type()->bytes());
+            writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+            fprintf(fp, "\treturn retval;\n");
+        } else {
+            if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n");
+            if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+        }
+        fprintf(fp, "}\n\n");
+    }
+
+    fprintf(fp, "}  // namespace\n\n");
+
+    // constructor
+    fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str());
+    fprintf(fp, "\tm_stream = stream;\n");
+    fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\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 \"ChecksumCalculator.h\"\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
+#if INSTRUMENT_TIMING_HOST
+    fprintf(fp, "#include \"time.h\"\n");
+#endif
+
+    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, ChecksumCalculator* checksumCalc);\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");
+
+    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);
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "\t%s = (%s_dec_%s_proc_t) getProc(\"%s\", userData);\n",
+                    e->name().c_str(),
+                    e->name().c_str(),
+                    sideString(side),
+                    e->name().c_str());
+        } else {
+            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();
+
+    bool changesChecksum = false;
+    for (size_t i = 0; i < size(); ++i) {
+        const EntryPoint& ep = at(i);
+        if (ep.name().find("SelectChecksum") != std::string::npos) {
+            changesChecksum = true;
+            break;
+        }
+    }
+
+    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 \"ChecksumCalculatorThreadInfo.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");
+
+    fprintf(fp,
+#if DECODER_CHECK_GL_ERRORS
+            "#define CHECK_GL_ERRORS\n"
+#endif
+            "#ifdef CHECK_GL_ERRORS\n"
+            "#  define SET_LASTCALL(name)  sprintf(lastCall, #name)\n"
+            "#else\n"
+            "#  define SET_LASTCALL(name)\n"
+            "#endif\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, ChecksumCalculator* checksumCalc) {\n", classname.c_str());
+    fprintf(fp,
+"\tif (len < 8) return 0; \n\
+#ifdef CHECK_GL_ERRORS\n\
+\tchar lastCall[256] = {0};\n\
+#endif\n\
+\tunsigned char *ptr = (unsigned char *)buf;\n\
+\tconst unsigned char* const end = (const unsigned char*)buf + len;\n");
+    if (!changesChecksum) {
+        fprintf(fp,
+R"(    const size_t checksumSize = checksumCalc->checksumByteSize();
+    const bool useChecksum = checksumSize > 0;
+)");
+    }
+    fprintf(fp,
+"\twhile (end - ptr >= 8) {\n\
+\t\tuint32_t opcode = *(uint32_t *)ptr;   \n\
+\t\tint32_t packetLen = *(int32_t *)(ptr + 4);\n\
+\t\tif (end - ptr < packetLen) return ptr - (unsigned char*)buf;\n");
+    if (changesChecksum) {
+        fprintf(fp,
+R"(        // Do this on every iteration, as some commands may change the checksum
+        // calculation parameters.
+        const size_t checksumSize = checksumCalc->checksumByteSize();
+        const bool useChecksum = checksumSize > 0;
+)");
+    }
+    fprintf(fp, "\t\tswitch(opcode) {\n");
+
+    for (size_t f = 0; f < n; f++) {
+        enum Pass_t {
+            PASS_FIRST = 0,
+            PASS_VariableDeclarations = PASS_FIRST,
+            PASS_Protocol,
+            PASS_TmpBuffAlloc,
+            PASS_MemAlloc,
+            PASS_DebugPrint,
+            PASS_FunctionCall,
+            PASS_FlushOutput,
+            PASS_Epilog,
+            PASS_LAST };
+        EntryPoint *e = &(*this)[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()) + " ";
+        }
+
+        // TODO - add for return value;
+        fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());
+        fprintf(fp, "\t\t\tandroid::base::beginTrace(\"%s decode\");\n", e->name().c_str());
+
+#if INSTRUMENT_TIMING_HOST
+        fprintf(fp, "\t\t\tstruct timespec ts0, ts1, ts2;\n");
+        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
+#endif
+        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();
+        }
+
+#define SKIP_DEBUG_PRINT 1
+
+        for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) {
+#if SKIP_DEBUG_PRINT
+            if (pass == PASS_DebugPrint) continue;
+#endif
+
+#if INSTRUMENT_TIMING_HOST
+            if (pass == PASS_FunctionCall) {
+                fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+            }
+#endif
+            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) {
+                if (e->customDecoder() && !e->notApi()) {
+                    fprintf(fp, "\t\t\tthis->%s_dec(", e->hostApiName().c_str());
+                } else {
+                    fprintf(fp, "\t\t\tthis->%s(", e->hostApiName().c_str());
+                }
+                if (e->customDecoder()) {
+                    fprintf(fp, "this"); // add a context to the call
+                }
+            } else if (pass == PASS_DebugPrint) {
+                if (strstr(m_basename.c_str(), "gl")) {
+                    fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");
+                    fprintf(fp, "\t\tGLint err = this->glGetError();\n");
+                    fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (pre-call): 0x%%X before %s\\n\", err);\n",
+                            m_basename.c_str(), e->name().c_str());
+                    fprintf(fp, "\t\t#endif\n");
+                }
+                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() && v->isDMA()) {
+                    if (pass == PASS_VariableDeclarations) {
+                        fprintf(fp,
+                                "\t\t\tuint64_t var_%s_guest_paddr = Unpack<uint64_t,uint64_t>(ptr + %s);\n"
+                                "\t\t\t%s var_%s = stream->getDmaForReading(var_%s_guest_paddr);\n",
+                                var_name,
+                                varoffset.c_str(),
+                                var_type_name,
+                                var_name,
+                                var_name);
+                    }
+                    if (pass == PASS_FunctionCall ||
+                        pass == PASS_DebugPrint) {
+                        fprintf(fp, "var_%s", var_name);
+                    }
+                    varoffset += " + 8";
+                }
+
+                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->isDMA()) {
+                    if (v->pointerDir() & Var::POINTER_IN) {
+                        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 (v->unpackExpression().size() > 0) {
+                                fprintf(fp,
+                                    "\t\t\tvoid* inptr_%s_unpacked;\n"
+                                    "\t\t\t%s;\n",
+                                    var_name,
+                                    v->unpackExpression().c_str());
+                            }
+
+                        }
+                        if (pass == PASS_FunctionCall &&
+                            v->pointerDir() == Var::POINTER_IN) {
+                            if (v->nullAllowed()) {
+                                fprintf(fp,
+                                        "size_%s == 0 ? nullptr : (%s)(inptr_%s.get())",
+                                        var_name,
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                if (v->unpackExpression().size() > 0) {
+                                    fprintf(fp,
+                                            "(%s)(inptr_%s_unpacked)",
+                                            var_type_name,
+                                            var_name);
+                                } else {
+                                    fprintf(fp,
+                                            "(%s)(inptr_%s.get())",
+                                            var_type_name,
+                                            var_name);
+                                }
+                            }
+                        } else if (pass == PASS_DebugPrint &&
+                                   v->pointerDir() == Var::POINTER_IN) {
+                            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 &&
+                            v->pointerDir() == Var::POINTER_IN) {
+                            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 &&
+                                   v->pointerDir() == Var::POINTER_IN) {
+                            fprintf(fp,
+                                    "(%s)(inptr_%s), size_%s",
+                                    var_type_name,
+                                    var_name,
+                                    var_name);
+                        }
+    #endif  // !USE_ALIGNED_BUFFERS
+                        varoffset += " + 4 + size_";
+                        varoffset += var_name;
+                    }
+                    if (v->pointerDir() & Var::POINTER_OUT)  { // 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);
+                            // If both input and output variable, initialize with the input.
+                            if (v->pointerDir() == Var::POINTER_INOUT) {
+                                fprintf(fp,
+                                        "\t\t\tmemcpy(outptr_%s.get(), inptr_%s.get(), size_%s);\n",
+                                        var_name,
+                                        var_name,
+                                        var_name);
+                            }
+
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp, "\t\t\tvoid* forPacking_%s = nullptr;\n", var_name);
+                            }
+                            if (v->hostPackTmpAllocExpression() != "") {
+                                fprintf(fp, "\t\t\t%s;\n", v->hostPackTmpAllocExpression().c_str());
+                            }
+                        } else if (pass == PASS_FunctionCall) {
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp,
+                                        "(%s)(forPacking_%s)",
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                if (v->nullAllowed()) {
+                                    fprintf(fp,
+                                            "size_%s == 0 ? nullptr : (%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) {
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp,
+                                        "\t\t\tif (size_%s) {\n"
+                                        "\t\t\t%s; }\n",
+                                        var_name,
+                                        v->hostPackExpression().c_str());
+                            }
+                            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
+                    if (v->pointerDir() == Var::POINTER_OUT) {
+                        varoffset += " + 4";
+                    }
+                    }
+                }
+            }
+
+            if (pass == PASS_Protocol) {
+                fprintf(fp,
+                        "\t\t\tif (useChecksum) {\n"
+                        "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, %s, "
+                        "ptr + %s, checksumSize, "
+                        "\n\t\t\t\t\t\"%s::decode,"
+                        " OP_%s: GL checksumCalculator failure\\n\");\n"
+                        "\t\t\t}\n",
+                        varoffset.c_str(),
+                        varoffset.c_str(),
+                        classname.c_str(),
+                        e->name().c_str()
+                        );
+
+                varoffset += " + 4";
+            }
+
+            if (pass == PASS_FunctionCall ||
+                pass == PASS_DebugPrint) {
+                fprintf(fp, ");\n");
+
+                if (pass == PASS_FunctionCall) {
+                    // unlock all dma buffers that have been passed
+                    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();
+                        if (v->isDMA()) {
+                            fprintf(fp,
+                                    "\t\t\tstream->unlockDma(var_%s_guest_paddr);\n",
+                                    var_name);
+                        }
+                    }
+                }
+            }
+
+            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\ttotalTmpSize += checksumSize;\n"
+                            "\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\tif (useChecksum) {\n"
+                            "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, "
+                            "&tmpBuf[0], totalTmpSize - checksumSize, "
+                            "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n"
+                            "\t\t\t}\n"
+                            "\t\t\tstream->flush();\n");
+                }
+            }
+        } // pass;
+
+#if INSTRUMENT_TIMING_HOST
+        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
+        fprintf(fp, "\t\t\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
+        fprintf(fp, "\t\t\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
+        fprintf(fp, "\t\t\tprintf(\"(timing) %%4ld.%%06ld %s: %%ld (%%ld) us\\n\", "
+                    "ts1.tv_sec, ts1.tv_nsec/1000, timeDiff, timeDiff2);\n", e->name().c_str());
+#endif
+        fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());
+        fprintf(fp, "\t\t\tandroid::base::endTrace();\n");
+        fprintf(fp, "\t\t\tbreak;\n");
+        fprintf(fp, "\t\t}\n");
+
+        delete [] tmpBufOffset;
+    }
+    fprintf(fp, "\t\tdefault:\n");
+    fprintf(fp, "\t\t\treturn ptr - (unsigned char*)buf;\n");
+    fprintf(fp, "\t\t} //switch\n");
+    if (strstr(m_basename.c_str(), "gl")) {
+        fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");
+        fprintf(fp, "\t\tGLint err = this->glGetError();\n");
+        fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (post-call): 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
+        fprintf(fp, "\t\t#endif\n");
+    }
+
+    fprintf(fp, "\t\tptr += packetLen;\n");
+    fprintf(fp, "\t} // while\n");
+    fprintf(fp, "\treturn ptr - (unsigned char*)buf;\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;
+}