More debugger support.

This lets you attach jdb. Quitting will let your program run to completion.
This also fixes the "class", "fields", and "methods" commands.

Change-Id: I6645f52dd8b5847454a553c31c80a2f5bf8f1000
diff --git a/src/debugger.cc b/src/debugger.cc
index 43448d8..38346e7 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -400,8 +400,8 @@
 }
 
 JDWP::RefTypeId Dbg::GetSuperclass(JDWP::RefTypeId id) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+  Class* c = gRegistry->Get<Class*>(id);
+  return gRegistry->Add(c->GetSuperClass());
 }
 
 JDWP::ObjectId Dbg::GetClassLoader(JDWP::RefTypeId id) {
@@ -484,9 +484,10 @@
   return 0;
 }
 
-const char* Dbg::GetSignature(JDWP::RefTypeId refTypeId) {
-  UNIMPLEMENTED(FATAL);
-  return NULL;
+std::string Dbg::GetSignature(JDWP::RefTypeId refTypeId) {
+  Class* c = gRegistry->Get<Class*>(refTypeId);
+  CHECK(c != NULL);
+  return c->GetDescriptor()->ToModifiedUtf8();
 }
 
 const char* Dbg::GetSourceFile(JDWP::RefTypeId refTypeId) {
@@ -554,16 +555,81 @@
   return NULL;
 }
 
-void Dbg::OutputAllFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
-  UNIMPLEMENTED(FATAL);
+/*
+ * Augment the access flags for synthetic methods and fields by setting
+ * the (as described by the spec) "0xf0000000 bit".  Also, strip out any
+ * flags not specified by the Java programming language.
+ */
+static uint32_t MangleAccessFlags(uint32_t accessFlags) {
+  accessFlags &= kAccJavaFlagsMask;
+  if ((accessFlags & kAccSynthetic) != 0) {
+    accessFlags |= 0xf0000000;
+  }
+  return accessFlags;
 }
 
-void Dbg::OutputAllMethods(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
-  UNIMPLEMENTED(FATAL);
+JDWP::FieldId ToFieldId(Field* f) {
+  return static_cast<JDWP::FieldId>(reinterpret_cast<uintptr_t>(f));
 }
 
-void Dbg::OutputAllInterfaces(JDWP::RefTypeId refTypeId, JDWP::ExpandBuf* pReply) {
-  UNIMPLEMENTED(FATAL);
+JDWP::MethodId ToMethodId(Method* m) {
+  return static_cast<JDWP::MethodId>(reinterpret_cast<uintptr_t>(m));
+}
+
+void Dbg::OutputDeclaredFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
+  Class* c = gRegistry->Get<Class*>(refTypeId);
+  CHECK(c != NULL);
+
+  size_t instance_field_count = c->NumInstanceFields();
+  size_t static_field_count = c->NumStaticFields();
+
+  expandBufAdd4BE(pReply, instance_field_count + static_field_count);
+
+  for (size_t i = 0; i < instance_field_count + static_field_count; ++i) {
+    Field* f = (i < instance_field_count) ? c->GetInstanceField(i) : c->GetStaticField(i - instance_field_count);
+
+    expandBufAddFieldId(pReply, ToFieldId(f));
+    expandBufAddUtf8String(pReply, f->GetName()->ToModifiedUtf8().c_str());
+    expandBufAddUtf8String(pReply, f->GetTypeDescriptor());
+    if (withGeneric) {
+      static const char genericSignature[1] = "";
+      expandBufAddUtf8String(pReply, genericSignature);
+    }
+    expandBufAdd4BE(pReply, MangleAccessFlags(f->GetAccessFlags()));
+  }
+}
+
+void Dbg::OutputDeclaredMethods(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
+  Class* c = gRegistry->Get<Class*>(refTypeId);
+  CHECK(c != NULL);
+
+  size_t direct_method_count = c->NumDirectMethods();
+  size_t virtual_method_count = c->NumVirtualMethods();
+
+  expandBufAdd4BE(pReply, direct_method_count + virtual_method_count);
+
+  for (size_t i = 0; i < direct_method_count + virtual_method_count; ++i) {
+    Method* m = (i < direct_method_count) ? c->GetDirectMethod(i) : c->GetVirtualMethod(i - direct_method_count);
+
+    expandBufAddMethodId(pReply, ToMethodId(m));
+    expandBufAddUtf8String(pReply, m->GetName()->ToModifiedUtf8().c_str());
+    expandBufAddUtf8String(pReply, m->GetSignature()->ToModifiedUtf8().c_str());
+    if (withGeneric) {
+      static const char genericSignature[1] = "";
+      expandBufAddUtf8String(pReply, genericSignature);
+    }
+    expandBufAdd4BE(pReply, MangleAccessFlags(m->GetAccessFlags()));
+  }
+}
+
+void Dbg::OutputDeclaredInterfaces(JDWP::RefTypeId refTypeId, JDWP::ExpandBuf* pReply) {
+  Class* c = gRegistry->Get<Class*>(refTypeId);
+  CHECK(c != NULL);
+  size_t interface_count = c->NumInterfaces();
+  expandBufAdd4BE(pReply, interface_count);
+  for (size_t i = 0; i < interface_count; ++i) {
+    expandBufAddRefTypeId(pReply, gRegistry->Add(c->GetInterface(i)));
+  }
 }
 
 void Dbg::OutputLineTable(JDWP::RefTypeId refTypeId, JDWP::MethodId methodId, JDWP::ExpandBuf* pReply) {
@@ -605,9 +671,20 @@
   return NULL;
 }
 
-char* Dbg::GetThreadName(JDWP::ObjectId threadId) {
-  UNIMPLEMENTED(FATAL);
-  return NULL;
+Thread* DecodeThread(JDWP::ObjectId threadId) {
+  Object* thread_peer = gRegistry->Get<Object*>(threadId);
+  CHECK(thread_peer != NULL);
+  return Thread::FromManagedThread(thread_peer);
+}
+
+bool Dbg::GetThreadName(JDWP::ObjectId threadId, std::string& name) {
+  ScopedThreadListLock thread_list_lock;
+  Thread* thread = DecodeThread(threadId);
+  if (thread == NULL) {
+    return false;
+  }
+  StringAppendF(&name, "<%d> %s", thread->GetThinLockId(), thread->GetName()->ToModifiedUtf8().c_str());
+  return true;
 }
 
 JDWP::ObjectId Dbg::GetThreadGroup(JDWP::ObjectId threadId) {
@@ -645,12 +722,6 @@
   return 0;
 }
 
-Thread* DecodeThread(JDWP::ObjectId threadId) {
-  Object* thread_peer = gRegistry->Get<Object*>(threadId);
-  CHECK(thread_peer != NULL);
-  return Thread::FromManagedThread(thread_peer);
-}
-
 bool Dbg::ThreadExists(JDWP::ObjectId threadId) {
   return DecodeThread(threadId) != NULL;
 }
@@ -710,8 +781,16 @@
 }
 
 int Dbg::GetThreadFrameCount(JDWP::ObjectId threadId) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+  struct CountStackDepthVisitor : public Thread::StackVisitor {
+    CountStackDepthVisitor() : depth(0) {}
+    virtual void VisitFrame(const Frame& frame, uintptr_t pc) {
+      ++depth;
+    }
+    size_t depth;
+  };
+  CountStackDepthVisitor visitor;
+  DecodeThread(threadId)->WalkStack(&visitor);
+  return visitor.depth;
 }
 
 bool Dbg::GetThreadFrame(JDWP::ObjectId threadId, int num, JDWP::FrameId* pFrameId, JDWP::JdwpLocation* pLoc) {
diff --git a/src/debugger.h b/src/debugger.h
index c2e8661..ca1d2a0 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -137,7 +137,7 @@
   static bool FindLoadedClassBySignature(const char* classDescriptor, JDWP::RefTypeId* pRefTypeId);
   static void GetObjectType(JDWP::ObjectId objectId, uint8_t* pRefTypeTag, JDWP::RefTypeId* pRefTypeId);
   static uint8_t GetClassObjectType(JDWP::RefTypeId refTypeId);
-  static const char* GetSignature(JDWP::RefTypeId refTypeId);
+  static std::string GetSignature(JDWP::RefTypeId refTypeId);
   static const char* GetSourceFile(JDWP::RefTypeId refTypeId);
   static const char* GetObjectTypeName(JDWP::ObjectId objectId);
   static uint8_t GetObjectTag(JDWP::ObjectId objectId);
@@ -158,9 +158,9 @@
    * Method and Field
    */
   static const char* GetMethodName(JDWP::RefTypeId refTypeId, JDWP::MethodId id);
-  static void OutputAllFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply);
-  static void OutputAllMethods(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply);
-  static void OutputAllInterfaces(JDWP::RefTypeId refTypeId, JDWP::ExpandBuf* pReply);
+  static void OutputDeclaredFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply);
+  static void OutputDeclaredMethods(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply);
+  static void OutputDeclaredInterfaces(JDWP::RefTypeId refTypeId, JDWP::ExpandBuf* pReply);
   static void OutputLineTable(JDWP::RefTypeId refTypeId, JDWP::MethodId methodId, JDWP::ExpandBuf* pReply);
   static void OutputVariableTable(JDWP::RefTypeId refTypeId, JDWP::MethodId id, bool withGeneric, JDWP::ExpandBuf* pReply);
 
@@ -176,7 +176,7 @@
   /*
    * Thread, ThreadGroup, Frame
    */
-  static char* GetThreadName(JDWP::ObjectId threadId);
+  static bool GetThreadName(JDWP::ObjectId threadId, std::string& name);
   static JDWP::ObjectId GetThreadGroup(JDWP::ObjectId threadId);
   static char* GetThreadGroupName(JDWP::ObjectId threadGroupId);
   static JDWP::ObjectId GetThreadGroupParent(JDWP::ObjectId threadGroupId);
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 23637db..9b18c14 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -477,8 +477,8 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
-  const char* signature = Dbg::GetSignature(refTypeId);
-  expandBufAddUtf8String(pReply, signature);
+  std::string signature(Dbg::GetSignature(refTypeId));
+  expandBufAddUtf8String(pReply, signature.c_str());
 
   return ERR_NONE;
 }
@@ -548,7 +548,7 @@
 
   LOG(VERBOSE) << StringPrintf("  Req for interfaces in %llx (%s)", refTypeId, Dbg::GetClassDescriptor(refTypeId).c_str());
 
-  Dbg::OutputAllInterfaces(refTypeId, pReply);
+  Dbg::OutputDeclaredInterfaces(refTypeId, pReply);
 
   return ERR_NONE;
 }
@@ -586,9 +586,9 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for signature of refTypeId=0x%llx", refTypeId);
-  const char* signature = Dbg::GetSignature(refTypeId);
+  std::string signature(Dbg::GetSignature(refTypeId));
   if (signature != NULL) {
-    expandBufAddUtf8String(pReply, signature);
+    expandBufAddUtf8String(pReply, signature.c_str());
   } else {
     LOG(WARNING) << StringPrintf("No signature for refTypeId=0x%llx", refTypeId);
     expandBufAddUtf8String(pReply, "Lunknown;");
@@ -617,8 +617,8 @@
 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));
-  Dbg::OutputAllFields(refTypeId, true, pReply);
+  LOG(VERBOSE) << StringPrintf("  --> '%s'", Dbg::GetSignature(refTypeId).c_str());
+  Dbg::OutputDeclaredFields(refTypeId, true, pReply);
   return ERR_NONE;
 }
 
@@ -630,9 +630,9 @@
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for methods in refTypeId=0x%llx", refTypeId);
-  LOG(VERBOSE) << StringPrintf("  --> '%s'", Dbg::GetSignature(refTypeId));
+  LOG(VERBOSE) << StringPrintf("  --> '%s'", Dbg::GetSignature(refTypeId).c_str());
 
-  Dbg::OutputAllMethods(refTypeId, true, pReply);
+  Dbg::OutputDeclaredMethods(refTypeId, true, pReply);
 
   return ERR_NONE;
 }
@@ -894,12 +894,12 @@
   ObjectId threadId = ReadObjectId(&buf);
 
   LOG(VERBOSE) << StringPrintf("  Req for name of thread 0x%llx", threadId);
-  char* name = Dbg::GetThreadName(threadId);
-  if (name == NULL) {
+  std::string name;
+  if (!Dbg::GetThreadName(threadId, name)) {
     return ERR_INVALID_THREAD;
   }
-  expandBufAddUtf8String(pReply, name);
-  free(name);
+  LOG(VERBOSE) << StringPrintf("  Name of thread 0x%llx is \"%s\"", threadId, name.c_str());
+  expandBufAddUtf8String(pReply, name.c_str());
 
   return ERR_NONE;
 }
@@ -987,7 +987,7 @@
     return ERR_INVALID_THREAD;
   }
   if (!Dbg::IsSuspended(threadId)) {
-    LOG(VERBOSE) << StringPrintf("  Rejecting req for frames in running thread '%s' (%llx)", Dbg::GetThreadName(threadId), threadId);
+    LOG(WARNING) << StringPrintf("  Rejecting req for frames in running thread %llx", threadId);
     return ERR_THREAD_NOT_SUSPENDED;
   }
 
@@ -1031,7 +1031,7 @@
     return ERR_INVALID_THREAD;
   }
   if (!Dbg::IsSuspended(threadId)) {
-    LOG(VERBOSE) << StringPrintf("  Rejecting req for frames in running thread '%s' (%llx)", Dbg::GetThreadName(threadId), threadId);
+    LOG(WARNING) << StringPrintf("  Rejecting req for frames in running thread %llx", threadId);
     return ERR_THREAD_NOT_SUSPENDED;
   }