Implement debugger support for the "threads" command.
Change-Id: I266d28ee00d87fdc7ecb179ddf52634db96e573c
diff --git a/src/debugger.cc b/src/debugger.cc
index 38346e7..7918bfb 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -476,7 +476,15 @@
}
void Dbg::GetObjectType(JDWP::ObjectId objectId, uint8_t* pRefTypeTag, JDWP::RefTypeId* pRefTypeId) {
- UNIMPLEMENTED(FATAL);
+ Object* o = gRegistry->Get<Object*>(objectId);
+ if (o->GetClass()->IsArrayClass()) {
+ *pRefTypeTag = JDWP::TT_ARRAY;
+ } else if (o->GetClass()->IsInterface()) {
+ *pRefTypeTag = JDWP::TT_INTERFACE;
+ } else {
+ *pRefTypeTag = JDWP::TT_CLASS;
+ }
+ *pRefTypeId = gRegistry->Add(o->GetClass());
}
uint8_t Dbg::GetClassObjectType(JDWP::RefTypeId refTypeId) {
@@ -688,13 +696,28 @@
}
JDWP::ObjectId Dbg::GetThreadGroup(JDWP::ObjectId threadId) {
- UNIMPLEMENTED(FATAL);
- return 0;
+ Object* thread = gRegistry->Get<Object*>(threadId);
+ CHECK(thread != NULL);
+
+ Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Thread;");
+ CHECK(c != NULL);
+ Field* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
+ CHECK(f != NULL);
+ Object* group = f->GetObject(thread);
+ CHECK(group != NULL);
+ return gRegistry->Add(group);
}
-char* Dbg::GetThreadGroupName(JDWP::ObjectId threadGroupId) {
- UNIMPLEMENTED(FATAL);
- return NULL;
+std::string Dbg::GetThreadGroupName(JDWP::ObjectId threadGroupId) {
+ Object* thread_group = gRegistry->Get<Object*>(threadGroupId);
+ CHECK(thread_group != NULL);
+
+ Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/ThreadGroup;");
+ CHECK(c != NULL);
+ Field* f = c->FindInstanceField("name", "Ljava/lang/String;");
+ CHECK(f != NULL);
+ String* s = reinterpret_cast<String*>(f->GetObject(thread_group));
+ return s->ToModifiedUtf8();
}
JDWP::ObjectId Dbg::GetThreadGroupParent(JDWP::ObjectId threadGroupId) {
@@ -702,19 +725,50 @@
return 0;
}
+static Object* GetStaticThreadGroup(const char* field_name) {
+ Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/ThreadGroup;");
+ CHECK(c != NULL);
+ Field* f = c->FindStaticField(field_name, "Ljava/lang/ThreadGroup;");
+ CHECK(f != NULL);
+ Object* group = f->GetObject(NULL);
+ CHECK(group != NULL);
+ return group;
+}
+
JDWP::ObjectId Dbg::GetSystemThreadGroupId() {
- UNIMPLEMENTED(FATAL);
- return 0;
+ return gRegistry->Add(GetStaticThreadGroup("mSystem"));
}
JDWP::ObjectId Dbg::GetMainThreadGroupId() {
- UNIMPLEMENTED(FATAL);
- return 0;
+ return gRegistry->Add(GetStaticThreadGroup("mMain"));
}
-bool Dbg::GetThreadStatus(JDWP::ObjectId threadId, uint32_t* threadStatus, uint32_t* suspendStatus) {
- UNIMPLEMENTED(FATAL);
- return false;
+bool Dbg::GetThreadStatus(JDWP::ObjectId threadId, uint32_t* pThreadStatus, uint32_t* pSuspendStatus) {
+ ScopedThreadListLock thread_list_lock;
+
+ Thread* thread = DecodeThread(threadId);
+ if (thread == NULL) {
+ return false;
+ }
+
+ switch (thread->GetState()) {
+ case Thread::kTerminated: *pThreadStatus = JDWP::TS_ZOMBIE; break;
+ case Thread::kRunnable: *pThreadStatus = JDWP::TS_RUNNING; break;
+ case Thread::kTimedWaiting: *pThreadStatus = JDWP::TS_SLEEPING; break;
+ case Thread::kBlocked: *pThreadStatus = JDWP::TS_MONITOR; break;
+ case Thread::kWaiting: *pThreadStatus = JDWP::TS_WAIT; break;
+ case Thread::kInitializing: *pThreadStatus = JDWP::TS_ZOMBIE; break;
+ case Thread::kStarting: *pThreadStatus = JDWP::TS_ZOMBIE; break;
+ case Thread::kNative: *pThreadStatus = JDWP::TS_RUNNING; break;
+ case Thread::kVmWait: *pThreadStatus = JDWP::TS_WAIT; break;
+ case Thread::kSuspended: *pThreadStatus = JDWP::TS_RUNNING; break;
+ default:
+ LOG(FATAL) << "unknown thread state " << thread->GetState();
+ }
+
+ *pSuspendStatus = (thread->IsSuspended() ? JDWP::SUSPEND_STATUS_SUSPENDED : 0);
+
+ return true;
}
uint32_t Dbg::GetThreadSuspendCount(JDWP::ObjectId threadId) {
diff --git a/src/debugger.h b/src/debugger.h
index ca1d2a0..ca39316 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -178,7 +178,7 @@
*/
static bool GetThreadName(JDWP::ObjectId threadId, std::string& name);
static JDWP::ObjectId GetThreadGroup(JDWP::ObjectId threadId);
- static char* GetThreadGroupName(JDWP::ObjectId threadGroupId);
+ static std::string GetThreadGroupName(JDWP::ObjectId threadGroupId);
static JDWP::ObjectId GetThreadGroupParent(JDWP::ObjectId threadGroupId);
static JDWP::ObjectId GetSystemThreadGroupId();
static JDWP::ObjectId GetMainThreadGroupId();
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 9b18c14..84e1afc 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -1082,15 +1082,7 @@
ObjectId threadGroupId = ReadObjectId(&buf);
LOG(VERBOSE) << StringPrintf(" Req for name of threadGroupId=0x%llx", threadGroupId);
- char* name = Dbg::GetThreadGroupName(threadGroupId);
- if (name != NULL) {
- expandBufAddUtf8String(pReply, name);
- } else {
- expandBufAddUtf8String(pReply, "BAD-GROUP-ID");
- LOG(VERBOSE) << StringPrintf("bad thread group ID");
- }
-
- free(name);
+ expandBufAddUtf8String(pReply, Dbg::GetThreadGroupName(threadGroupId).c_str());
return ERR_NONE;
}
diff --git a/src/thread.h b/src/thread.h
index dca983f..823b72c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -68,12 +68,12 @@
kMaxPriority = 10,
};
enum State {
- // These match up with JDWP values.
- kTerminated = 0, // TERMINATED
- kRunnable = 1, // RUNNABLE or running now
- kTimedWaiting = 2, // TIMED_WAITING in Object.wait()
- kBlocked = 3, // BLOCKED on a monitor
- kWaiting = 4, // WAITING in Object.wait()
+ // These correspond to JDWP states (but needn't share the same values).
+ kTerminated = 0, // TS_ZOMBIE
+ kRunnable = 1, // TS_RUNNING
+ kTimedWaiting = 2, // TS_SLEEPING in Object.wait()
+ kBlocked = 3, // TS_MONITOR on a monitor
+ kWaiting = 4, // TS_WAIT in Object.wait()
// Non-JDWP states.
kInitializing = 5, // allocated, not yet running --- TODO: unnecessary?
kStarting = 6, // native thread started, not yet ready to run managed code