More JDWP robustness.

We pass a lot more JDWP tests with this (fewer total failures than dalvik,
because although dalvik implements more requests, it assumes that the debuggers
only send it valid input).

I've also added some of the missing constants (there are tests of modifier 12,
SourceNameMatch, which was added in Java 6).

Change-Id: I502e87b50fb305c5c8b061421339c8ceab104640
diff --git a/src/jdwp/jdwp_bits.h b/src/jdwp/jdwp_bits.h
index 344d2de..5536c52 100644
--- a/src/jdwp/jdwp_bits.h
+++ b/src/jdwp/jdwp_bits.h
@@ -67,19 +67,15 @@
 }
 
 /*
- * Read a UTF-8 string into newly-allocated storage, and null-terminate it.
- *
- * Returns the string and its length.  (The latter is probably unnecessary
- * for the way we're using UTF8.)
+ * Reads a UTF-8 string into a std::string.
  */
-static inline char* ReadNewUtf8String(unsigned char const** ppSrc, size_t* pLength) {
+static inline std::string ReadNewUtf8String(unsigned char const** ppSrc) {
   uint32_t length = Read4BE(ppSrc);
-  char* buf = (char*) malloc(length+1);
-  memcpy(buf, *ppSrc, length);
-  buf[length] = '\0';
+  std::string s;
+  s.resize(length);
+  memcpy(&s[0], *ppSrc, length);
   (*ppSrc) += length;
-  *pLength = length;
-  return buf;
+  return s;
 }
 
 static inline void Append1BE(std::vector<uint8_t>& bytes, uint8_t value) {
diff --git a/src/jdwp/jdwp_constants.cc b/src/jdwp/jdwp_constants.cc
index 7110eed..ab4e841 100644
--- a/src/jdwp/jdwp_constants.cc
+++ b/src/jdwp/jdwp_constants.cc
@@ -40,6 +40,8 @@
     return "THREAD_NOT_SUSPENDED";
   case ERR_THREAD_SUSPENDED:
     return "THREAD_SUSPENDED";
+  case ERR_THREAD_NOT_ALIVE:
+    return "THREAD_NOT_ALIVE";
   case ERR_INVALID_OBJECT:
     return "INVALID_OBJEC";
   case ERR_INVALID_CLASS:
@@ -157,7 +159,7 @@
   case EK_EXCEPTION:          return "EXCEPTION";
   case EK_USER_DEFINED:       return "USER_DEFINED";
   case EK_THREAD_START:       return "THREAD_START";
-  /*case EK_THREAD_END:         return "THREAD_END";*/
+  case EK_THREAD_DEATH:       return "THREAD_DEATH";
   case EK_CLASS_PREPARE:      return "CLASS_PREPARE";
   case EK_CLASS_UNLOAD:       return "CLASS_UNLOAD";
   case EK_CLASS_LOAD:         return "CLASS_LOAD";
@@ -166,11 +168,14 @@
   case EK_EXCEPTION_CATCH:    return "EXCEPTION_CATCH";
   case EK_METHOD_ENTRY:       return "METHOD_ENTRY";
   case EK_METHOD_EXIT:        return "METHOD_EXIT";
-  case EK_VM_INIT:            return "VM_INIT";
+  case EK_METHOD_EXIT_WITH_RETURN_VALUE: return "METHOD_EXIT_WITH_RETURN_VALUE";
+  case EK_MONITOR_CONTENDED_ENTER:       return "MONITOR_CONTENDED_ENTER";
+  case EK_MONITOR_CONTENDED_ENTERED:     return "MONITOR_CONTENDED_ENTERED";
+  case EK_MONITOR_WAIT:       return "MONITOR_WAIT";
+  case EK_MONITOR_WAITED:     return "MONITOR_WAITED";
+  case EK_VM_START:           return "VM_START";
   case EK_VM_DEATH:           return "VM_DEATH";
   case EK_VM_DISCONNECTED:    return "VM_DISCONNECTED";
-  /*case EK_VM_START:           return "VM_START";*/
-  case EK_THREAD_DEATH:       return "THREAD_DEATH";
   default:                    return "?UNKNOWN?";
   }
 }
@@ -179,24 +184,24 @@
   return os;
 }
 
-const char* ModKindStr(JdwpModKind kind) {
-  switch (kind) {
-  case MK_COUNT:              return "COUNT";
-  case MK_CONDITIONAL:        return "CONDITIONAL";
-  case MK_THREAD_ONLY:        return "THREAD_ONLY";
-  case MK_CLASS_ONLY:         return "CLASS_ONLY";
-  case MK_CLASS_MATCH:        return "CLASS_MATCH";
-  case MK_CLASS_EXCLUDE:      return "CLASS_EXCLUDE";
-  case MK_LOCATION_ONLY:      return "LOCATION_ONLY";
-  case MK_EXCEPTION_ONLY:     return "EXCEPTION_ONLY";
-  case MK_FIELD_ONLY:         return "FIELD_ONLY";
-  case MK_STEP:               return "STEP";
-  case MK_INSTANCE_ONLY:      return "INSTANCE_ONLY";
-  default:                    return "?UNKNOWN?";
-  }
-}
 std::ostream& operator<<(std::ostream& os, const JdwpModKind& value) {
-  os << ModKindStr(value);
+  switch (value) {
+  case MK_COUNT:             os << "COUNT"; break;
+  case MK_CONDITIONAL:       os << "CONDITIONAL"; break;
+  case MK_THREAD_ONLY:       os << "THREAD_ONLY"; break;
+  case MK_CLASS_ONLY:        os << "CLASS_ONLY"; break;
+  case MK_CLASS_MATCH:       os << "CLASS_MATCH"; break;
+  case MK_CLASS_EXCLUDE:     os << "CLASS_EXCLUDE"; break;
+  case MK_LOCATION_ONLY:     os << "LOCATION_ONLY"; break;
+  case MK_EXCEPTION_ONLY:    os << "EXCEPTION_ONLY"; break;
+  case MK_FIELD_ONLY:        os << "FIELD_ONLY"; break;
+  case MK_STEP:              os << "STEP"; break;
+  case MK_INSTANCE_ONLY:     os << "INSTANCE_ONLY"; break;
+  case MK_SOURCE_NAME_MATCH: os << "SOURCE_NAME_MATCH"; break;
+  default:
+    os << "JdwpModKind[" << static_cast<int>(value) << "]";
+    break;
+  }
   return os;
 }
 
diff --git a/src/jdwp/jdwp_constants.h b/src/jdwp/jdwp_constants.h
index 6d550f2..14dc6cf 100644
--- a/src/jdwp/jdwp_constants.h
+++ b/src/jdwp/jdwp_constants.h
@@ -35,6 +35,7 @@
   ERR_INVALID_PRIORITY                            = 12,
   ERR_THREAD_NOT_SUSPENDED                        = 13,
   ERR_THREAD_SUSPENDED                            = 14,
+  ERR_THREAD_NOT_ALIVE                            = 15,
   ERR_INVALID_OBJECT                              = 20,
   ERR_INVALID_CLASS                               = 21,
   ERR_CLASS_NOT_PREPARED                          = 22,
@@ -110,7 +111,7 @@
   EK_EXCEPTION            = 4,
   EK_USER_DEFINED         = 5,
   EK_THREAD_START         = 6,
-  EK_THREAD_END           = 7,
+  EK_THREAD_DEATH         = 7, // Formerly known as THREAD_END.
   EK_CLASS_PREPARE        = 8,
   EK_CLASS_UNLOAD         = 9,
   EK_CLASS_LOAD           = 10,
@@ -119,11 +120,14 @@
   EK_EXCEPTION_CATCH      = 30,
   EK_METHOD_ENTRY         = 40,
   EK_METHOD_EXIT          = 41,
-  EK_VM_INIT              = 90,
+  EK_METHOD_EXIT_WITH_RETURN_VALUE = 42,
+  EK_MONITOR_CONTENDED_ENTER       = 43,
+  EK_MONITOR_CONTENDED_ENTERED     = 44,
+  EK_MONITOR_WAIT         = 45,
+  EK_MONITOR_WAITED       = 46,
+  EK_VM_START             = 90, // Formerly known as VM_INIT.
   EK_VM_DEATH             = 99,
-  EK_VM_DISCONNECTED      = 100,  /* "Never sent across JDWP */
-  EK_VM_START             = EK_VM_INIT,
-  EK_THREAD_DEATH         = EK_THREAD_END,
+  EK_VM_DISCONNECTED      = 100, // "Never sent across JDWP".
 };
 std::ostream& operator<<(std::ostream& os, const JdwpEventKind& value);
 
@@ -142,6 +146,7 @@
   MK_FIELD_ONLY           = 9,
   MK_STEP                 = 10,
   MK_INSTANCE_ONLY        = 11,
+  MK_SOURCE_NAME_MATCH    = 12, // Since Java 6.
 };
 std::ostream& operator<<(std::ostream& os, const JdwpModKind& value);
 
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index 22d3c24..a405c9b 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -128,7 +128,7 @@
 
   for (int i = 0; i < pEvent->modCount; i++) {
     const JdwpEventMod* pMod = &pEvent->mods[i];
-    LOG(INFO) << "  " << static_cast<JdwpModKind>(pMod->modKind);
+    LOG(INFO) << "  " << pMod->modKind;
     /* TODO - show details */
   }
 }
@@ -451,8 +451,7 @@
       }
       break;
     default:
-      LOG(ERROR) << "unhandled mod kind " << pMod->modKind;
-      CHECK(false);
+      LOG(FATAL) << "unknown mod kind " << pMod->modKind;
       break;
     }
   }
@@ -544,7 +543,6 @@
     SetWaitForEventThread(Dbg::GetThreadSelfId());
 
     /* leave pReq->invoke_needed_ raised so we can check reentrancy */
-    LOG(VERBOSE) << "invoking method...";
     Dbg::ExecuteMethod(pReq);
 
     pReq->error = ERR_NONE;
diff --git a/src/jdwp/jdwp_event.h b/src/jdwp/jdwp_event.h
index 5f18595..e8f633f 100644
--- a/src/jdwp/jdwp_event.h
+++ b/src/jdwp/jdwp_event.h
@@ -30,54 +30,54 @@
  * Event modifiers.  A JdwpEvent may have zero or more of these.
  */
 union JdwpEventMod {
-  uint8_t      modKind;                /* JdwpModKind */
+  JdwpModKind modKind;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     int         count;
   } count;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     uint32_t          exprId;
   } conditional;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     ObjectId    threadId;
   } threadOnly;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     RefTypeId   refTypeId;
   } classOnly;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     char*       classPattern;
   } classMatch;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     char*       classPattern;
   } classExclude;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     JdwpLocation loc;
   } locationOnly;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     uint8_t          caught;
     uint8_t          uncaught;
     RefTypeId   refTypeId;
   } exceptionOnly;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     RefTypeId   refTypeId;
     FieldId     fieldId;
   } fieldOnly;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     ObjectId    threadId;
     int         size;           /* JdwpStepSize */
     int         depth;          /* JdwpStepDepth */
   } step;
   struct {
-    uint8_t          modKind;
+    JdwpModKind modKind;
     ObjectId    objectId;
   } instanceOnly;
 };
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index a11c805..9f23af1 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -194,8 +194,7 @@
  * been loaded by multiple class loaders.
  */
 static JdwpError handleVM_ClassesBySignature(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  size_t strLen;
-  char* classDescriptor = ReadNewUtf8String(&buf, &strLen);
+  std::string classDescriptor(ReadNewUtf8String(&buf));
   LOG(VERBOSE) << "  Req for class by signature '" << classDescriptor << "'";
 
   std::vector<RefTypeId> ids;
@@ -207,15 +206,15 @@
     // Get class vs. interface and status flags.
     JDWP::JdwpTypeTag typeTag;
     uint32_t status;
-    Dbg::GetClassInfo(ids[i], &typeTag, &status, NULL);
+    if (!Dbg::GetClassInfo(ids[i], &typeTag, &status, NULL)) {
+      return ERR_INVALID_CLASS;
+    }
 
     expandBufAdd1(pReply, typeTag);
     expandBufAddRefTypeId(pReply, ids[i]);
     expandBufAdd4BE(pReply, status);
   }
 
-  free(classDescriptor);
-
   return ERR_NONE;
 }
 
@@ -324,16 +323,12 @@
  * string "java.util.Arrays".)
  */
 static JdwpError handleVM_CreateString(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  size_t strLen;
-  char* str = ReadNewUtf8String(&buf, &strLen);
-
+  std::string str(ReadNewUtf8String(&buf));
   LOG(VERBOSE) << "  Req to create string '" << str << "'";
-
   ObjectId stringId = Dbg::CreateString(str);
   if (stringId == 0) {
     return ERR_OUT_OF_MEMORY;
   }
-
   expandBufAddObjectId(pReply, stringId);
   return ERR_NONE;
 }
@@ -425,30 +420,27 @@
  * Cough up the complete list of classes.
  */
 static JdwpError handleVM_AllClassesWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  uint32_t numClasses = 0;
-  RefTypeId* classRefBuf = NULL;
+  std::vector<JDWP::RefTypeId> classes;
+  Dbg::GetClassList(classes);
 
-  Dbg::GetClassList(&numClasses, &classRefBuf);
+  expandBufAdd4BE(pReply, classes.size());
 
-  expandBufAdd4BE(pReply, numClasses);
-
-  for (uint32_t i = 0; i < numClasses; i++) {
+  for (size_t i = 0; i < classes.size(); ++i) {
     static const char genericSignature[1] = "";
     JDWP::JdwpTypeTag refTypeTag;
     std::string descriptor;
     uint32_t status;
-
-    Dbg::GetClassInfo(classRefBuf[i], &refTypeTag, &status, &descriptor);
+    if (!Dbg::GetClassInfo(classes[i], &refTypeTag, &status, &descriptor)) {
+      return ERR_INVALID_CLASS;
+    }
 
     expandBufAdd1(pReply, refTypeTag);
-    expandBufAddRefTypeId(pReply, classRefBuf[i]);
+    expandBufAddRefTypeId(pReply, classes[i]);
     expandBufAddUtf8String(pReply, descriptor);
     expandBufAddUtf8String(pReply, genericSignature);
     expandBufAdd4BE(pReply, status);
   }
 
-  free(classRefBuf);
-
   return ERR_NONE;
 }
 
@@ -460,9 +452,11 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
-  std::string signature(Dbg::GetSignature(refTypeId));
+  std::string signature;
+  if (!Dbg::GetSignature(refTypeId, signature)) {
+    return ERR_INVALID_CLASS;
+  }
   expandBufAddUtf8String(pReply, signature);
-
   return ERR_NONE;
 }
 
@@ -471,8 +465,11 @@
  */
 static JdwpError handleRT_Modifiers(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
-  uint32_t modBits = Dbg::GetAccessFlags(refTypeId);
-  expandBufAdd4BE(pReply, modBits);
+  uint32_t access_flags;
+  if (!Dbg::GetAccessFlags(refTypeId, access_flags)) {
+    return ERR_INVALID_CLASS;
+  }
+  expandBufAdd4BE(pReply, access_flags);
   return ERR_NONE;
 }
 
@@ -512,11 +509,11 @@
  */
 static JdwpError handleRT_Status(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
-
-  /* get status flags */
   JDWP::JdwpTypeTag typeTag;
   uint32_t status;
-  Dbg::GetClassInfo(refTypeId, &typeTag, &status, NULL);
+  if (!Dbg::GetClassInfo(refTypeId, &typeTag, &status, NULL)) {
+    return ERR_INVALID_CLASS;
+  }
   expandBufAdd4BE(pReply, status);
   return ERR_NONE;
 }
@@ -526,12 +523,8 @@
  */
 static JdwpError handleRT_Interfaces(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
-
   LOG(VERBOSE) << StringPrintf("  Req for interfaces in %llx (%s)", refTypeId, Dbg::GetClassDescriptor(refTypeId).c_str());
-
-  Dbg::OutputDeclaredInterfaces(refTypeId, pReply);
-
-  return ERR_NONE;
+  return Dbg::OutputDeclaredInterfaces(refTypeId, pReply) ? ERR_NONE : ERR_INVALID_CLASS;
 }
 
 /*
@@ -539,12 +532,12 @@
  */
 static JdwpError handleRT_ClassObject(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
-  ObjectId classObjId = Dbg::GetClassObject(refTypeId);
-
-  LOG(VERBOSE) << StringPrintf("  RefTypeId %llx -> ObjectId %llx", refTypeId, classObjId);
-
-  expandBufAddObjectId(pReply, classObjId);
-
+  ObjectId classObjectId;
+  if (!Dbg::GetClassObject(refTypeId, classObjectId)) {
+    return ERR_INVALID_CLASS;
+  }
+  LOG(VERBOSE) << StringPrintf("  RefTypeId %llx -> ObjectId %llx", refTypeId, classObjectId);
+  expandBufAddObjectId(pReply, classObjectId);
   return ERR_NONE;
 }
 
@@ -567,8 +560,8 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
-  std::string signature(Dbg::GetSignature(refTypeId));
-  if (signature != NULL) {
+  std::string signature;
+  if (Dbg::GetSignature(refTypeId, signature)) {
     expandBufAddUtf8String(pReply, signature);
   } else {
     LOG(WARNING) << StringPrintf("No signature for refTypeId=0x%llx", refTypeId);
@@ -591,16 +584,27 @@
   return ERR_NONE;
 }
 
+static std::string Describe(const RefTypeId& refTypeId) {
+  std::string signature("unknown");
+  Dbg::GetSignature(refTypeId, signature);
+  return StringPrintf("refTypeId=0x%llx (%s)", refTypeId, signature.c_str());
+}
+
 /*
  * Given a referenceTypeId, return a block of stuff that describes the
  * fields declared by a class.
  */
 static JdwpError handleRT_FieldsWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
-  LOG(VERBOSE) << StringPrintf("  Req for fields in refTypeId=0x%llx", refTypeId);
-  LOG(VERBOSE) << StringPrintf("  --> '%s'", Dbg::GetSignature(refTypeId).c_str());
-  Dbg::OutputDeclaredFields(refTypeId, true, pReply);
-  return ERR_NONE;
+  LOG(VERBOSE) << "  Req for fields in " << Describe(refTypeId);
+  return Dbg::OutputDeclaredFields(refTypeId, true, pReply) ? ERR_NONE : ERR_INVALID_CLASS;
+}
+
+// Obsolete equivalent of FieldsWithGeneric, without the generic type information.
+static JdwpError handleRT_Fields(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
+  RefTypeId refTypeId = ReadRefTypeId(&buf);
+  LOG(VERBOSE) << "  Req for fields in " << Describe(refTypeId);
+  return Dbg::OutputDeclaredFields(refTypeId, false, pReply) ? ERR_NONE : ERR_INVALID_CLASS;
 }
 
 /*
@@ -609,13 +613,15 @@
  */
 static JdwpError handleRT_MethodsWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
+  LOG(VERBOSE) << "  Req for methods in " << Describe(refTypeId);
+  return Dbg::OutputDeclaredMethods(refTypeId, true, pReply) ? ERR_NONE : ERR_INVALID_CLASS;
+}
 
-  LOG(VERBOSE) << StringPrintf("  Req for methods in refTypeId=0x%llx", refTypeId);
-  LOG(VERBOSE) << StringPrintf("  --> '%s'", Dbg::GetSignature(refTypeId).c_str());
-
-  Dbg::OutputDeclaredMethods(refTypeId, true, pReply);
-
-  return ERR_NONE;
+// Obsolete equivalent of MethodsWithGeneric, without the generic type information.
+static JdwpError handleRT_Methods(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
+  RefTypeId refTypeId = ReadRefTypeId(&buf);
+  LOG(VERBOSE) << "  Req for methods in " << Describe(refTypeId);
+  return Dbg::OutputDeclaredMethods(refTypeId, false, pReply) ? ERR_NONE : ERR_INVALID_CLASS;
 }
 
 /*
@@ -623,11 +629,11 @@
  */
 static JdwpError handleCT_Superclass(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId classId = ReadRefTypeId(&buf);
-
-  RefTypeId superClassId = Dbg::GetSuperclass(classId);
-
+  RefTypeId superClassId;
+  if (!Dbg::GetSuperclass(classId, superClassId)) {
+    return ERR_INVALID_CLASS;
+  }
   expandBufAddRefTypeId(pReply, superClassId);
-
   return ERR_NONE;
 }
 
@@ -680,7 +686,10 @@
   MethodId methodId = ReadMethodId(&buf);
 
   LOG(VERBOSE) << "Creating instance of " << Dbg::GetClassDescriptor(classId);
-  ObjectId objectId = Dbg::CreateObject(classId);
+  ObjectId objectId;
+  if (!Dbg::CreateObject(classId, objectId)) {
+    return ERR_INVALID_CLASS;
+  }
   if (objectId == 0) {
     return ERR_OUT_OF_MEMORY;
   }
@@ -695,7 +704,10 @@
   uint32_t length = Read4BE(&buf);
 
   LOG(VERBOSE) << StringPrintf("Creating array %s[%u]", Dbg::GetClassDescriptor(arrayTypeId).c_str(), length);
-  ObjectId objectId = Dbg::CreateArrayObject(arrayTypeId, length);
+  ObjectId objectId;
+  if (!Dbg::CreateArrayObject(arrayTypeId, length, objectId)) {
+    return ERR_INVALID_CLASS;
+  }
   if (objectId == 0) {
     return ERR_OUT_OF_MEMORY;
   }
@@ -860,7 +872,7 @@
   ObjectId stringObject = ReadObjectId(&buf);
   std::string str(Dbg::StringToUtf8(stringObject));
 
-  LOG(VERBOSE) << StringPrintf("  Req for str %llx --> '%s'", stringObject, str.c_str());
+  LOG(VERBOSE) << StringPrintf("  Req for str %llx --> '%s'", stringObject, PrintableString(str).c_str());
 
   expandBufAddUtf8String(pReply, str);
 
@@ -1248,7 +1260,7 @@
    * mods in JDWP doc).
    */
   for (uint32_t idx = 0; idx < modifierCount; idx++) {
-    uint8_t modKind = Read1(&buf);
+    JdwpModKind modKind = static_cast<JdwpModKind>(Read1(&buf));
 
     pEvent->mods[idx].modKind = modKind;
 
@@ -1286,25 +1298,17 @@
       break;
     case MK_CLASS_MATCH:    /* restrict events to matching classes */
       {
-        char* pattern;
-        size_t strLen;
-
-        pattern = ReadNewUtf8String(&buf, &strLen);
-        LOG(VERBOSE) << StringPrintf("    ClassMatch: '%s'", pattern);
+        std::string pattern(ReadNewUtf8String(&buf));
+        LOG(VERBOSE) << StringPrintf("    ClassMatch: '%s'", pattern.c_str());
         /* pattern is "java.foo.*", we want "java/foo/ *" */
-        pEvent->mods[idx].classMatch.classPattern = dvmDotToSlash(pattern);
-        free(pattern);
+        pEvent->mods[idx].classMatch.classPattern = dvmDotToSlash(pattern.c_str());
       }
       break;
     case MK_CLASS_EXCLUDE:  /* restrict events to non-matching classes */
       {
-        char* pattern;
-        size_t strLen;
-
-        pattern = ReadNewUtf8String(&buf, &strLen);
-        LOG(VERBOSE) << StringPrintf("    ClassExclude: '%s'", pattern);
-        pEvent->mods[idx].classExclude.classPattern = dvmDotToSlash(pattern);
-        free(pattern);
+        std::string pattern(ReadNewUtf8String(&buf));
+        LOG(VERBOSE) << StringPrintf("    ClassExclude: '%s'", pattern.c_str());
+        pEvent->mods[idx].classExclude.classPattern = dvmDotToSlash(pattern.c_str());
       }
       break;
     case MK_LOCATION_ONLY:  /* restrict certain events based on loc */
@@ -1496,12 +1500,12 @@
 
   LOG(VERBOSE) << StringPrintf("  Req for refTypeId for class=%llx (%s)", classObjectId, Dbg::GetClassDescriptor(classObjectId).c_str());
 
-  /* just hand the type back to them */
-  if (Dbg::IsInterface(classObjectId)) {
-    expandBufAdd1(pReply, TT_INTERFACE);
-  } else {
-    expandBufAdd1(pReply, TT_CLASS);
+  bool is_interface;
+  if (!Dbg::IsInterface(classObjectId, is_interface)) {
+    return ERR_INVALID_CLASS;
   }
+
+  expandBufAdd1(pReply, is_interface ? TT_INTERFACE : TT_CLASS);
   expandBufAddRefTypeId(pReply, classObjectId);
 
   return ERR_NONE;
@@ -1587,8 +1591,8 @@
   { 2,    1,  handleRT_Signature,     "ReferenceType.Signature" },
   { 2,    2,  handleRT_ClassLoader,   "ReferenceType.ClassLoader" },
   { 2,    3,  handleRT_Modifiers,     "ReferenceType.Modifiers" },
-  { 2,    4,  NULL, "ReferenceType.Fields" },
-  { 2,    5,  NULL, "ReferenceType.Methods" },
+  { 2,    4,  handleRT_Fields,        "ReferenceType.Fields" },
+  { 2,    5,  handleRT_Methods,       "ReferenceType.Methods" },
   { 2,    6,  handleRT_GetValues,     "ReferenceType.GetValues" },
   { 2,    7,  handleRT_SourceFile,    "ReferenceType.SourceFile" },
   { 2,    8,  NULL, "ReferenceType.NestedTypes" },