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