Implement enough JDWP functionality that we can attach jdb.

You can also try "classes" and "classpath", though anything else
deadlocks because we're suspended but jdb thinks we aren't. I don't
think that's a new bug with this patch, though, so I'll look at that
next.

Change-Id: I54456b6a7fe72642be696c66aa485dc0c8a7f913
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index 6b5ef8c..8e0d4c3 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -109,7 +109,7 @@
  */
 struct ModBasket {
   const JdwpLocation* pLoc;           /* LocationOnly */
-  const char*         className;      /* ClassMatch/ClassExclude */
+  std::string         className;      /* ClassMatch/ClassExclude */
   ObjectId            threadId;       /* ThreadOnly */
   RefTypeId           classId;        /* ClassOnly */
   RefTypeId           excepClassId;   /* ExceptionOnly */
@@ -374,23 +374,22 @@
  *
  * ("Restricted name globbing" might have been a better term.)
  */
-static bool patternMatch(const char* pattern, const char* target) {
-  int patLen = strlen(pattern);
+static bool patternMatch(const char* pattern, const std::string& target) {
+  size_t patLen = strlen(pattern);
 
   if (pattern[0] == '*') {
-    int targetLen = strlen(target);
     patLen--;
     // TODO: remove printf when we find a test case to verify this
-    LOG(ERROR) << ">>> comparing '" << (pattern + 1) << "' to '" << (target + (targetLen-patLen)) << "'";
+    LOG(ERROR) << ">>> comparing '" << (pattern + 1) << "' to '" << (target.c_str() + (target.size()-patLen)) << "'";
 
-    if (targetLen < patLen) {
+    if (target.size() < patLen) {
       return false;
     }
-    return strcmp(pattern+1, target + (targetLen-patLen)) == 0;
+    return strcmp(pattern+1, target.c_str() + (target.size()-patLen)) == 0;
   } else if (pattern[patLen-1] == '*') {
-    return strncmp(pattern, target, patLen-1) == 0;
+    return strncmp(pattern, target.c_str(), patLen-1) == 0;
   } else {
-    return strcmp(pattern, target) == 0;
+    return strcmp(pattern, target.c_str()) == 0;
   }
 }
 
@@ -734,8 +733,8 @@
 
 // TODO: This doesn't behave like the real dvmDescriptorToName.
 // I'm hoping this isn't used to communicate with the debugger, and we can just use descriptors.
-char* dvmDescriptorToName(const char* descriptor) {
-  return strdup(descriptor);
+std::string dvmDescriptorToName(const std::string& descriptor) {
+  return descriptor;
 }
 
 /*
@@ -761,14 +760,13 @@
  */
 bool PostLocationEvent(JdwpState* state, const JdwpLocation* pLoc, ObjectId thisPtr, int eventFlags) {
   ModBasket basket;
-  char* nameAlloc = NULL;
 
   memset(&basket, 0, sizeof(basket));
   basket.pLoc = pLoc;
   basket.classId = pLoc->classId;
   basket.thisPtr = thisPtr;
   basket.threadId = Dbg::GetThreadSelfId();
-  basket.className = nameAlloc = dvmDescriptorToName(Dbg::GetClassDescriptor(pLoc->classId));
+  basket.className = dvmDescriptorToName(Dbg::GetClassDescriptor(pLoc->classId));
 
   /*
    * On rare occasions we may need to execute interpreted code in the VM
@@ -778,7 +776,6 @@
    */
   if (basket.threadId == state->debugThreadId) {
     LOG(VERBOSE) << "Ignoring location event in JDWP thread";
-    free(nameAlloc);
     return false;
   }
 
@@ -793,7 +790,6 @@
    */
   if (invokeInProgress(state)) {
     LOG(VERBOSE) << "Not checking breakpoints during invoke (" << basket.className << ")";
-    free(nameAlloc);
     return false;
   }
 
@@ -854,7 +850,6 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  free(nameAlloc);
   return matchCount != 0;
 }
 
@@ -963,13 +958,12 @@
     const JdwpLocation* pCatchLoc, ObjectId thisPtr)
 {
   ModBasket basket;
-  char* nameAlloc = NULL;
 
   memset(&basket, 0, sizeof(basket));
   basket.pLoc = pThrowLoc;
   basket.classId = pThrowLoc->classId;
   basket.threadId = Dbg::GetThreadSelfId();
-  basket.className = nameAlloc = dvmDescriptorToName(Dbg::GetClassDescriptor(basket.classId));
+  basket.className = dvmDescriptorToName(Dbg::GetClassDescriptor(basket.classId));
   basket.excepClassId = exceptionClassId;
   basket.caught = (pCatchLoc->classId != 0);
   basket.thisPtr = thisPtr;
@@ -977,7 +971,6 @@
   /* don't try to post an exception caused by the debugger */
   if (invokeInProgress(state)) {
     LOG(VERBOSE) << "Not posting exception hit during invoke (" << basket.className << ")";
-    free(nameAlloc);
     return false;
   }
 
@@ -998,14 +991,14 @@
                  << " caught=" << basket.caught << ")";
     LOG(VERBOSE) << StringPrintf("  throw: %d %llx %x %lld (%s.%s)", pThrowLoc->typeTag,
         pThrowLoc->classId, pThrowLoc->methodId, pThrowLoc->idx,
-        Dbg::GetClassDescriptor(pThrowLoc->classId),
+        Dbg::GetClassDescriptor(pThrowLoc->classId).c_str(),
         Dbg::GetMethodName(pThrowLoc->classId, pThrowLoc->methodId));
     if (pCatchLoc->classId == 0) {
       LOG(VERBOSE) << "  catch: (not caught)";
     } else {
       LOG(VERBOSE) << StringPrintf("  catch: %d %llx %x %lld (%s.%s)", pCatchLoc->typeTag,
           pCatchLoc->classId, pCatchLoc->methodId, pCatchLoc->idx,
-          Dbg::GetClassDescriptor(pCatchLoc->classId),
+          Dbg::GetClassDescriptor(pCatchLoc->classId).c_str(),
           Dbg::GetMethodName(pCatchLoc->classId, pCatchLoc->methodId));
     }
 
@@ -1047,7 +1040,6 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  free(nameAlloc);
   return matchCount != 0;
 }
 
@@ -1059,17 +1051,15 @@
  */
 bool PostClassPrepare(JdwpState* state, int tag, RefTypeId refTypeId, const char* signature, int status) {
   ModBasket basket;
-  char* nameAlloc = NULL;
 
   memset(&basket, 0, sizeof(basket));
   basket.classId = refTypeId;
   basket.threadId = Dbg::GetThreadSelfId();
-  basket.className = nameAlloc = dvmDescriptorToName(Dbg::GetClassDescriptor(basket.classId));
+  basket.className = dvmDescriptorToName(Dbg::GetClassDescriptor(basket.classId));
 
   /* suppress class prep caused by debugger */
   if (invokeInProgress(state)) {
     LOG(VERBOSE) << "Not posting class prep caused by invoke (" << basket.className << ")";
-    free(nameAlloc);
     return false;
   }
 
@@ -1114,7 +1104,7 @@
 
       expandBufAdd1(pReq, tag);
       expandBufAdd8BE(pReq, refTypeId);
-      expandBufAddUtf8String(pReq, (const uint8_t*) signature);
+      expandBufAddUtf8String(pReq, signature);
       expandBufAdd4BE(pReq, status);
     }
   }
@@ -1135,7 +1125,6 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  free(nameAlloc);
   return matchCount != 0;
 }
 
diff --git a/src/jdwp/jdwp_expand_buf.cc b/src/jdwp/jdwp_expand_buf.cc
index f5e24b2..30ebf00 100644
--- a/src/jdwp/jdwp_expand_buf.cc
+++ b/src/jdwp/jdwp_expand_buf.cc
@@ -153,8 +153,7 @@
   pBuf->curLen += sizeof(val);
 }
 
-static void SetUtf8String(uint8_t* buf, const uint8_t* str) {
-  uint32_t strLen = strlen((const char*)str);
+static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) {
   Set4BE(buf, strLen);
   memcpy(buf + sizeof(uint32_t), str, strLen);
 }
@@ -167,11 +166,11 @@
  * they can be null-terminated (either they don't have null bytes or they
  * have stored null bytes in a multi-byte encoding).
  */
-void expandBufAddUtf8String(ExpandBuf* pBuf, const uint8_t* str) {
-  int strLen = strlen((const char*)str);
+void expandBufAddUtf8String(ExpandBuf* pBuf, const char* str) {
+  int strLen = strlen(str);
 
   ensureSpace(pBuf, sizeof(uint32_t) + strLen);
-  SetUtf8String(pBuf->storage + pBuf->curLen, str);
+  SetUtf8String(pBuf->storage + pBuf->curLen, str, strLen);
   pBuf->curLen += sizeof(uint32_t) + strLen;
 }
 
diff --git a/src/jdwp/jdwp_expand_buf.h b/src/jdwp/jdwp_expand_buf.h
index 2c19f54..287f05e 100644
--- a/src/jdwp/jdwp_expand_buf.h
+++ b/src/jdwp/jdwp_expand_buf.h
@@ -56,7 +56,7 @@
 void expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val);
 void expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val);
 void expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val);
-void expandBufAddUtf8String(ExpandBuf* pBuf, const uint8_t* str);
+void expandBufAddUtf8String(ExpandBuf* pBuf, const char* str);
 
 }  // namespace JDWP
 
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 04c4734..e5e18bb 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -109,7 +109,7 @@
   uint32_t numArgs = Read4BE(&buf);
 
   LOG(VERBOSE) << StringPrintf("    --> threadId=%llx objectId=%llx", threadId, objectId);
-  LOG(VERBOSE) << StringPrintf("        classId=%llx methodId=%x %s.%s", classId, methodId, Dbg::GetClassDescriptor(classId), Dbg::GetMethodName(classId, methodId));
+  LOG(VERBOSE) << StringPrintf("        classId=%llx methodId=%x %s.%s", classId, methodId, Dbg::GetClassDescriptor(classId).c_str(), Dbg::GetMethodName(classId, methodId));
   LOG(VERBOSE) << StringPrintf("        %d args:", numArgs);
 
   uint64_t* argArray = NULL;
@@ -178,14 +178,14 @@
 static JdwpError handleVM_Version(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   /* text information on runtime version */
   std::string version(StringPrintf("Android Runtime %s", Runtime::Current()->GetVersion()));
-  expandBufAddUtf8String(pReply, (const uint8_t*) version.c_str());
+  expandBufAddUtf8String(pReply, version.c_str());
   /* JDWP version numbers */
   expandBufAdd4BE(pReply, 1);        // major
   expandBufAdd4BE(pReply, 5);        // minor
   /* VM JRE version */
-  expandBufAddUtf8String(pReply, (const uint8_t*) "1.6.0");  /* e.g. 1.6.0_22 */
+  expandBufAddUtf8String(pReply, "1.6.0");  /* e.g. 1.6.0_22 */
   /* target VM name */
-  expandBufAddUtf8String(pReply, (const uint8_t*) "DalvikVM");
+  expandBufAddUtf8String(pReply, "DalvikVM");
 
   return ERR_NONE;
 }
@@ -382,10 +382,10 @@
   uint32_t classPaths = 1;
   uint32_t bootClassPaths = 0;
 
-  expandBufAddUtf8String(pReply, (const uint8_t*) baseDir);
+  expandBufAddUtf8String(pReply, baseDir);
   expandBufAdd4BE(pReply, classPaths);
   for (uint32_t i = 0; i < classPaths; i++) {
-    expandBufAddUtf8String(pReply, (const uint8_t*) ".");
+    expandBufAddUtf8String(pReply, ".");
   }
 
   expandBufAdd4BE(pReply, bootClassPaths);
@@ -450,16 +450,16 @@
   expandBufAdd4BE(pReply, numClasses);
 
   for (uint32_t i = 0; i < numClasses; i++) {
-    static const uint8_t genericSignature[1] = "";
+    static const char genericSignature[1] = "";
     uint8_t refTypeTag;
-    const char* signature;
+    std::string descriptor;
     uint32_t status;
 
-    Dbg::GetClassInfo(classRefBuf[i], &refTypeTag, &status, &signature);
+    Dbg::GetClassInfo(classRefBuf[i], &refTypeTag, &status, &descriptor);
 
     expandBufAdd1(pReply, refTypeTag);
     expandBufAddRefTypeId(pReply, classRefBuf[i]);
-    expandBufAddUtf8String(pReply, (const uint8_t*) signature);
+    expandBufAddUtf8String(pReply, descriptor.c_str());
     expandBufAddUtf8String(pReply, genericSignature);
     expandBufAdd4BE(pReply, status);
   }
@@ -478,7 +478,7 @@
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
   const char* signature = Dbg::GetSignature(refTypeId);
-  expandBufAddUtf8String(pReply, (const uint8_t*) signature);
+  expandBufAddUtf8String(pReply, signature);
 
   return ERR_NONE;
 }
@@ -519,7 +519,7 @@
 
   const char* fileName = Dbg::GetSourceFile(refTypeId);
   if (fileName != NULL) {
-    expandBufAddUtf8String(pReply, (const uint8_t*) fileName);
+    expandBufAddUtf8String(pReply, fileName);
     return ERR_NONE;
   } else {
     return ERR_ABSENT_INFORMATION;
@@ -546,8 +546,7 @@
 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));
+  LOG(VERBOSE) << StringPrintf("  Req for interfaces in %llx (%s)", refTypeId, Dbg::GetClassDescriptor(refTypeId).c_str());
 
   Dbg::OutputAllInterfaces(refTypeId, pReply);
 
@@ -582,17 +581,17 @@
  * Like RT_Signature but with the possibility of a "generic signature".
  */
 static JdwpError handleRT_SignatureWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  static const uint8_t genericSignature[1] = "";
+  static const char genericSignature[1] = "";
 
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
   const char* signature = Dbg::GetSignature(refTypeId);
   if (signature != NULL) {
-    expandBufAddUtf8String(pReply, (const uint8_t*) signature);
+    expandBufAddUtf8String(pReply, signature);
   } else {
     LOG(WARNING) << StringPrintf("No signature for refTypeId=0x%llx", refTypeId);
-    expandBufAddUtf8String(pReply, (const uint8_t*) "Lunknown;");
+    expandBufAddUtf8String(pReply, "Lunknown;");
   }
   expandBufAddUtf8String(pReply, genericSignature);
 
@@ -714,7 +713,7 @@
   RefTypeId arrayTypeId = ReadRefTypeId(&buf);
   uint32_t length = Read4BE(&buf);
 
-  LOG(VERBOSE) << StringPrintf("Creating array %s[%u]", Dbg::GetClassDescriptor(arrayTypeId), length);
+  LOG(VERBOSE) << StringPrintf("Creating array %s[%u]", Dbg::GetClassDescriptor(arrayTypeId).c_str(), length);
   ObjectId objectId = Dbg::CreateArrayObject(arrayTypeId, length);
   if (objectId == 0) {
     return ERR_OUT_OF_MEMORY;
@@ -731,7 +730,7 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
   MethodId methodId = ReadMethodId(&buf);
 
-  LOG(VERBOSE) << StringPrintf("  Req for line table in %s.%s", Dbg::GetClassDescriptor(refTypeId), Dbg::GetMethodName(refTypeId,methodId));
+  LOG(VERBOSE) << StringPrintf("  Req for line table in %s.%s", Dbg::GetClassDescriptor(refTypeId).c_str(), Dbg::GetMethodName(refTypeId,methodId));
 
   Dbg::OutputLineTable(refTypeId, methodId, pReply);
 
@@ -745,9 +744,7 @@
   RefTypeId classId = ReadRefTypeId(&buf);
   MethodId methodId = ReadMethodId(&buf);
 
-  LOG(VERBOSE) << StringPrintf("  Req for LocalVarTab in class=%s method=%s",
-  Dbg::GetClassDescriptor(classId),
-  Dbg::GetMethodName(classId, methodId));
+  LOG(VERBOSE) << StringPrintf("  Req for LocalVarTab in class=%s method=%s", Dbg::GetClassDescriptor(classId).c_str(), Dbg::GetMethodName(classId, methodId));
 
   /*
    * We could return ERR_ABSENT_INFORMATION here if the DEX file was
@@ -884,7 +881,7 @@
 
   LOG(VERBOSE) << StringPrintf("  Req for str %llx --> '%s'", stringObject, str);
 
-  expandBufAddUtf8String(pReply, (uint8_t*) str);
+  expandBufAddUtf8String(pReply, str);
   free(str);
 
   return ERR_NONE;
@@ -901,7 +898,7 @@
   if (name == NULL) {
     return ERR_INVALID_THREAD;
   }
-  expandBufAddUtf8String(pReply, (uint8_t*) name);
+  expandBufAddUtf8String(pReply, name);
   free(name);
 
   return ERR_NONE;
@@ -1086,9 +1083,9 @@
 
   char* name = Dbg::GetThreadGroupName(threadGroupId);
   if (name != NULL) {
-    expandBufAddUtf8String(pReply, (uint8_t*) name);
+    expandBufAddUtf8String(pReply, name);
   } else {
-    expandBufAddUtf8String(pReply, (uint8_t*) "BAD-GROUP-ID");
+    expandBufAddUtf8String(pReply, "BAD-GROUP-ID");
     LOG(VERBOSE) << StringPrintf("bad thread group ID");
   }
 
@@ -1310,7 +1307,7 @@
     case MK_CLASS_ONLY:     /* for ClassPrepare, MethodEntry */
       {
         RefTypeId clazzId = ReadRefTypeId(&buf);
-        LOG(VERBOSE) << StringPrintf("    ClassOnly: %llx (%s)", clazzId, Dbg::GetClassDescriptor(clazzId));
+        LOG(VERBOSE) << StringPrintf("    ClassOnly: %llx (%s)", clazzId, Dbg::GetClassDescriptor(clazzId).c_str());
         pEvent->mods[idx].classOnly.refTypeId = clazzId;
       }
       break;
@@ -1356,7 +1353,7 @@
         caught = Read1(&buf);
         uncaught = Read1(&buf);
         LOG(VERBOSE) << StringPrintf("    ExceptionOnly: type=%llx(%s) caught=%d uncaught=%d",
-            exceptionOrNull, (exceptionOrNull == 0) ? "null" : Dbg::GetClassDescriptor(exceptionOrNull), caught, uncaught);
+            exceptionOrNull, (exceptionOrNull == 0) ? "null" : Dbg::GetClassDescriptor(exceptionOrNull).c_str(), caught, uncaught);
 
         pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull;
         pEvent->mods[idx].exceptionOnly.caught = caught;
@@ -1524,7 +1521,7 @@
 static JdwpError handleCOR_ReflectedType(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId classObjectId = ReadRefTypeId(&buf);
 
-  LOG(VERBOSE) << StringPrintf("  Req for refTypeId for class=%llx (%s)", classObjectId, Dbg::GetClassDescriptor(classObjectId));
+  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)) {
@@ -1732,7 +1729,7 @@
      * active debugger session, and zero out the last-activity timestamp
      * so waitForDebugger() doesn't return if we stall for a bit here.
      */
-    Dbg::Active();
+    Dbg::GoActive();
     QuasiAtomicSwap64(0, &lastActivityWhen);
   }