aboutsummaryrefslogtreecommitdiffstats
path: root/emulator
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2014-09-13 04:11:11 +0200
committerbohu <bohu@google.com>2014-11-25 12:30:46 -0800
commitdafaabf0b0243c30c81d6121cb1b84cfc37be806 (patch)
tree4ea20326bbb0c62166bb8e5c6d7a556b6f97b45b /emulator
parent6d8c4451b903dfef27a668908c1a986bd89c6109 (diff)
downloadsdk-dafaabf0b0243c30c81d6121cb1b84cfc37be806.zip
sdk-dafaabf0b0243c30c81d6121cb1b84cfc37be806.tar.gz
sdk-dafaabf0b0243c30c81d6121cb1b84cfc37be806.tar.bz2
emulator/opengl/emugen: Use templates to read values from stream.
The decoder didn't properly handle GLsizeiptr and GLintptr values, which are always 32-bit on the wire, but can be 64-bit on the host. I.e. it did something like that to read them from the stream: *(GLsizeiptr*)(ptr + offset) This fixes the issue by using templates to generate host-type-specific functions that properly read data from the stream and convert it to the appropriate host type. Change-Id: I75749bd715456ca143eb1713498f7cf635918801
Diffstat (limited to 'emulator')
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.cpp215
-rw-r--r--emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h107
2 files changed, 249 insertions, 73 deletions
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp
index 2e4c8d1..a92ad39 100644
--- a/emulator/opengl/host/tools/emugen/ApiGen.cpp
+++ b/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -761,9 +761,13 @@ int ApiGen::genDecoderImpl(const std::string &filename)
fprintf(fp, "\n\n#include <string.h>\n");
fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
+ fprintf(fp, "#include \"ProtocolUtils.h\"\n\n");
fprintf(fp, "#include <stdio.h>\n\n");
fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
+ // helper templates
+ fprintf(fp, "using namespace emugl;\n\n");
+
// decoder switch;
fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
fprintf(fp,
@@ -808,7 +812,9 @@ int ApiGen::genDecoderImpl(const std::string &filename)
}
for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
- if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
+ if (pass == PASS_FunctionCall &&
+ !e->retval().isVoid() &&
+ !e->retval().isPointer()) {
fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
totalTmpBuffOffset.c_str());
}
@@ -821,9 +827,14 @@ int ApiGen::genDecoderImpl(const std::string &filename)
}
} else if (pass == PASS_DebugPrint) {
fprintf(fp, "#ifdef DEBUG_PRINTOUT\n");
- fprintf(fp, "\t\t\tfprintf(stderr,\"%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, ",");
+ fprintf(fp,
+ "\t\t\tfprintf(stderr,\"%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
@@ -831,89 +842,147 @@ int ApiGen::genDecoderImpl(const std::string &filename)
// allocate memory for out pointers;
for (size_t j = 0; j < evars.size(); j++) {
Var *v = & evars[j];
- if (!v->isVoid()) {
- if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", ");
- if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", ");
+ if (v->isVoid()) {
+ continue;
+ }
+ if ((pass == PASS_FunctionCall) &&
+ (j != 0 || e->customDecoder())) {
+ fprintf(fp, ", ");
+ }
+ if (pass == PASS_DebugPrint && j != 0) {
+ fprintf(fp, ", ");
+ }
- if (!v->isPointer()) {
- if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
- fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
+ if (!v->isPointer()) {
+ if (pass == PASS_FunctionCall) {
+ fprintf(fp,
+ "Unpack<%s,uint%d_t>(ptr + %s)",
+ v->type()->name().c_str(),
+ v->type()->bytes() * 8,
+ varoffset.c_str());
+ }
+ if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "*(uint%d_t *)(ptr + %s)",
+ v->type()->bytes() * 8,
+ varoffset.c_str());
+ }
+ varoffset += " + " + toString(v->type()->bytes());
+ continue;
+ }
+
+ if (v->pointerDir() == Var::POINTER_IN ||
+ v->pointerDir() == Var::POINTER_INOUT) {
+ if (pass == PASS_MemAlloc &&
+ v->pointerDir() == Var::POINTER_INOUT) {
+ fprintf(fp,
+ "\t\t\tsize_t tmpPtr%uSize = (size_t)*(uint32_t *)(ptr + %s);\n",
+ (unsigned) j,
+ varoffset.c_str());
+ fprintf(fp,
+ "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
+ (unsigned) j,
+ varoffset.c_str());
+ }
+ if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "*((uint32_t *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)",
+ varoffset.c_str(),
+ v->type()->name().c_str(),
+ varoffset.c_str());
+ } else {
+ fprintf(fp,
+ "(%s)(ptr + %s + 4)",
+ v->type()->name().c_str(),
+ varoffset.c_str());
}
- varoffset += " + " + toString(v->type()->bytes());
- } else {
- if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) {
- if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) {
- fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
- (unsigned) j, varoffset.c_str());
- fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
- (unsigned) j, varoffset.c_str());
- }
- if (pass == PASS_FunctionCall) {
- if (v->nullAllowed()) {
- fprintf(fp, "*((unsigned int *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)",
- varoffset.c_str(), v->type()->name().c_str(), varoffset.c_str());
- } else {
- fprintf(fp, "(%s)(ptr + %s + 4)",
- v->type()->name().c_str(), varoffset.c_str());
- }
- } else if (pass == PASS_DebugPrint) {
- fprintf(fp, "(%s)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
- v->type()->name().c_str(), varoffset.c_str(),
- varoffset.c_str());
- }
- varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")";
- } else { // out pointer;
- if (pass == PASS_TmpBuffAlloc) {
- fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
- (unsigned) j, varoffset.c_str());
- if (!totalTmpBuffExist) {
- fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (unsigned)j);
- } else {
- fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (unsigned)j);
- }
- tmpBufOffset[j] = totalTmpBuffOffset;
- char tmpPtrName[16];
- sprintf(tmpPtrName," + tmpPtr%uSize", (unsigned)j);
- totalTmpBuffOffset += std::string(tmpPtrName);
- totalTmpBuffExist = true;
- } else if (pass == PASS_MemAlloc) {
- fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
- (unsigned)j, tmpBufOffset[j].c_str());
- fprintf(fp, "\t\t\tmemset(tmpPtr%u, 0, %s);\n",
- (unsigned)j,
- toString(v->type()->bytes()).c_str());
- } else if (pass == PASS_FunctionCall) {
- if (v->nullAllowed()) {
- fprintf(fp, "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)",
- (unsigned) j, v->type()->name().c_str(), (unsigned) j);
- } else {
- fprintf(fp, "(%s)(tmpPtr%u)", v->type()->name().c_str(), (unsigned) j);
- }
- } else if (pass == PASS_DebugPrint) {
- fprintf(fp, "(%s)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
- v->type()->name().c_str(), (unsigned) j,
- varoffset.c_str());
- }
- varoffset += " + 4";
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(ptr + %s + 4), *(uint32_t *)(ptr + %s)",
+ v->type()->name().c_str(),
+ varoffset.c_str(),
+ varoffset.c_str());
+ }
+ varoffset +=
+ " + 4 + *(tsize_t *)(ptr +" + varoffset + ")";
+ } else { // out pointer;
+ if (pass == PASS_TmpBuffAlloc) {
+ fprintf(fp,
+ "\t\t\tsize_t tmpPtr%uSize = (size_t)*(uint32_t *)(ptr + %s);\n",
+ (unsigned) j,
+ varoffset.c_str());
+ if (!totalTmpBuffExist) {
+ fprintf(fp,
+ "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n",
+ (unsigned)j);
+ } else {
+ fprintf(fp,
+ "\t\t\ttotalTmpSize += tmpPtr%uSize;\n",
+ (unsigned)j);
}
+ tmpBufOffset[j] = totalTmpBuffOffset;
+ char tmpPtrName[16];
+ sprintf(tmpPtrName," + tmpPtr%uSize", (unsigned)j);
+ totalTmpBuffOffset += std::string(tmpPtrName);
+ totalTmpBuffExist = true;
+ } else if (pass == PASS_MemAlloc) {
+ fprintf(fp,
+ "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
+ (unsigned)j,
+ tmpBufOffset[j].c_str());
+ fprintf(fp,
+ "\t\t\tmemset(tmpPtr%u, 0, %s);\n",
+ (unsigned)j,
+ toString(v->type()->bytes()).c_str());
+ } else if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)",
+ (unsigned) j,
+ v->type()->name().c_str(),
+ (unsigned) j);
+ } else {
+ fprintf(fp,
+ "(%s)(tmpPtr%u)",
+ v->type()->name().c_str(),
+ (unsigned) j);
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(tmpPtr%u), *(uint32_t *)(ptr + %s)",
+ v->type()->name().c_str(),
+ (unsigned) j,
+ varoffset.c_str());
}
+ varoffset += " + 4";
}
}
- if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
- if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
+ if (pass == PASS_FunctionCall ||
+ pass == PASS_DebugPrint) {
+ fprintf(fp, ");\n");
+ }
+ if (pass == PASS_DebugPrint) {
+ fprintf(fp, "#endif\n");
+ }
if (pass == PASS_TmpBuffAlloc) {
if (!e->retval().isVoid() && !e->retval().isPointer()) {
if (!totalTmpBuffExist)
- fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str());
+ 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());
+ fprintf(fp,
+ "\t\t\ttotalTmpSize += sizeof(%s);\n",
+ retvalType.c_str());
totalTmpBuffExist = true;
}
if (totalTmpBuffExist) {
- fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
+ fprintf(fp,
+ "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
}
}
@@ -923,8 +992,8 @@ int ApiGen::genDecoderImpl(const std::string &filename)
fprintf(fp, "\t\t\tstream->flush();\n");
}
- fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
- fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
+ fprintf(fp, "\t\t\tpos += *(uint32_t *)(ptr + 4);\n");
+ fprintf(fp, "\t\t\tptr += *(uint32_t *)(ptr + 4);\n");
}
} // pass;
diff --git a/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h
new file mode 100644
index 0000000..1198bd1
--- /dev/null
+++ b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h
@@ -0,0 +1,107 @@
+#ifndef EMUGL_PROTOCOL_UTILS_H
+#define EMUGL_PROTOCOL_UTILS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace emugl {
+
+// Helper macro
+#define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 }
+
+// Helper template: is_pointer.
+// is_pointer<T>::value is true iff |T| is a pointer type.
+template <typename T> struct is_pointer {
+ static const bool value = false;
+};
+
+template <typename T> struct is_pointer<T*> {
+ static const bool value = true;
+};
+
+// A helper template to extract values form the wire protocol stream
+// and convert them to appropriate host values.
+//
+// The wire protocol uses 32-bit exclusively when transferring
+// GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
+// from the guest (even when the guest is 64-bit).
+//
+// The corresponding host definitions depend on the host bitness. For
+// example, GLintptr is 64-bit on linux-x86_64. The following is a set
+// of templates that can simplify the conversion of protocol values
+// into host ones.
+//
+// The most important one is:
+//
+// unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
+//
+// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
+// sized-integer specifier (e.g. 'uint32_t'), and converting the result
+// into a |HOST_TYPE| value. For example:
+//
+// unpack<EGLImage,uint32_t>(ptr + 12);
+//
+// will read a 4-byte value from |ptr + 12| and convert it into
+// an EGLImage, which is a host void*. The template detects host
+// pointer types to perform proper type casting.
+//
+// TODO(digit): Add custom unpackers to handle generic opaque void* values.
+// and map them to unique 32-bit values.
+
+template <typename T, typename S, bool IS_POINTER>
+struct UnpackerT {};
+
+template <typename T, typename S>
+struct UnpackerT<T,S,false> {
+ static inline T unpack(const void* ptr) {
+ COMPILE_ASSERT(sizeof(T) == sizeof(S));
+ return (T)(*(S*)(ptr));
+ }
+};
+
+template <typename T, typename S>
+struct UnpackerT<T,S,true> {
+ static inline T unpack(const void* ptr) {
+ return (T)(uintptr_t)(*(S*)(ptr));
+ }
+};
+
+template <>
+struct UnpackerT<float,uint32_t,false> {
+ static inline float unpack(const void* ptr) {
+ union {
+ float f;
+ uint32_t u;
+ } v;
+ v.u = *(uint32_t*)(ptr);
+ return v.f;
+ }
+};
+
+template <>
+struct UnpackerT<double,uint64_t,false> {
+ static inline double unpack(const void* ptr) {
+ union {
+ double d;
+ uint32_t u;
+ } v;
+ v.u = *(uint64_t*)(ptr);
+ return v.d;
+ }
+};
+
+template <>
+struct UnpackerT<ssize_t,uint32_t,false> {
+ static inline ssize_t unpack(const void* ptr) {
+ return (ssize_t)*(int32_t*)(ptr);
+ }
+};
+
+template <typename T, typename S>
+inline T Unpack(const void* ptr) {
+ return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr);
+}
+
+} // namespace emugl
+
+#endif // EMUGL_PROTOCOL_UTILS_H