diff options
Diffstat (limited to 'runtime/jdwp')
-rw-r--r-- | runtime/jdwp/jdwp.h | 32 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_event.cc | 401 |
2 files changed, 264 insertions, 169 deletions
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h index b5b6298b84..0c9451ceeb 100644 --- a/runtime/jdwp/jdwp.h +++ b/runtime/jdwp/jdwp.h @@ -36,8 +36,13 @@ union JValue; class Thread; namespace mirror { + class ArtField; class ArtMethod; + class Class; + class Object; + class Throwable; } // namespace mirror +class Thread; namespace JDWP { @@ -65,6 +70,11 @@ static inline void expandBufAddObjectId(ExpandBuf* pReply, ObjectId id) { expand static inline void expandBufAddRefTypeId(ExpandBuf* pReply, RefTypeId id) { expandBufAdd8BE(pReply, id); } static inline void expandBufAddFrameId(ExpandBuf* pReply, FrameId id) { expandBufAdd8BE(pReply, id); } +struct EventLocation { + mirror::ArtMethod* method; + uint32_t dex_pc; +}; + /* * Holds a JDWP "location". */ @@ -178,7 +188,7 @@ struct JdwpState { * The VM has finished initializing. Only called when the debugger is * connected at the time initialization completes. */ - bool PostVMStart() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool PostVMStart() LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * A location of interest has been reached. This is used for breakpoints, @@ -192,8 +202,9 @@ struct JdwpState { * * "returnValue" is non-null for MethodExit events only. */ - bool PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, int eventFlags, + bool PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags, const JValue* returnValue) + LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* @@ -203,8 +214,9 @@ struct JdwpState { * "fieldValue" is non-null for field modification events only. * "is_modification" is true for field modification, false for field access. */ - bool PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, FieldId fieldId, - ObjectId thisPtr, const JValue* fieldValue, bool is_modification) + bool PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr, + const JValue* fieldValue, bool is_modification) + LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* @@ -212,21 +224,23 @@ struct JdwpState { * * Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught. */ - bool PostException(const JdwpLocation* pThrowLoc, ObjectId excepId, RefTypeId excepClassId, - const JdwpLocation* pCatchLoc, ObjectId thisPtr) + bool PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object, + const EventLocation* pCatchLoc, mirror::Object* thisPtr) + LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * A thread has started or stopped. */ - bool PostThreadChange(ObjectId threadId, bool start) + bool PostThreadChange(Thread* thread, bool start) + LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * Class has been prepared. */ - bool PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std::string& signature, - int status) + bool PostClassPrepare(mirror::Class* klass) + LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index fc39cc48d0..46db63ccd5 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -27,6 +27,9 @@ #include "jdwp/jdwp_constants.h" #include "jdwp/jdwp_expand_buf.h" #include "jdwp/jdwp_priv.h" +#include "jdwp/object_registry.h" +#include "mirror/art_field-inl.h" +#include "scoped_thread_state_change.h" #include "thread-inl.h" /* @@ -107,18 +110,17 @@ namespace JDWP { * The rest will be zeroed. */ struct ModBasket { - ModBasket() : pLoc(NULL), threadId(0), classId(0), excepClassId(0), - caught(false), fieldTypeID(0), fieldId(0), thisPtr(0) { } - - const JdwpLocation* pLoc; /* LocationOnly */ - std::string className; /* ClassMatch/ClassExclude */ - ObjectId threadId; /* ThreadOnly */ - RefTypeId classId; /* ClassOnly */ - RefTypeId excepClassId; /* ExceptionOnly */ - bool caught; /* ExceptionOnly */ - RefTypeId fieldTypeID; /* FieldOnly */ - FieldId fieldId; /* FieldOnly */ - ObjectId thisPtr; /* InstanceOnly */ + ModBasket() : pLoc(nullptr), thread(nullptr), locationClass(nullptr), exceptionClass(nullptr), + caught(false), field(nullptr), thisPtr(nullptr) { } + + const EventLocation* pLoc; /* LocationOnly */ + std::string className; /* ClassMatch/ClassExclude */ + Thread* thread; /* ThreadOnly */ + mirror::Class* locationClass; /* ClassOnly */ + mirror::Class* exceptionClass; /* ExceptionOnly */ + bool caught; /* ExceptionOnly */ + mirror::ArtField* field; /* FieldOnly */ + mirror::Object* thisPtr; /* InstanceOnly */ /* nothing for StepOnly -- handled differently */ }; @@ -463,12 +465,12 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) CHECK(false); // should not be getting these break; case MK_THREAD_ONLY: - if (pMod->threadOnly.threadId != basket.threadId) { + if (!Dbg::MatchThread(pMod->threadOnly.threadId, basket.thread)) { return false; } break; case MK_CLASS_ONLY: - if (!Dbg::MatchType(basket.classId, pMod->classOnly.refTypeId)) { + if (!Dbg::MatchType(basket.locationClass, pMod->classOnly.refTypeId)) { return false; } break; @@ -483,33 +485,32 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) } break; case MK_LOCATION_ONLY: - if (pMod->locationOnly.loc != *basket.pLoc) { + if (!Dbg::MatchLocation(pMod->locationOnly.loc, *basket.pLoc)) { return false; } break; case MK_EXCEPTION_ONLY: - if (pMod->exceptionOnly.refTypeId != 0 && !Dbg::MatchType(basket.excepClassId, pMod->exceptionOnly.refTypeId)) { + if (pMod->exceptionOnly.refTypeId != 0 && + !Dbg::MatchType(basket.exceptionClass, pMod->exceptionOnly.refTypeId)) { return false; } - if ((basket.caught && !pMod->exceptionOnly.caught) || (!basket.caught && !pMod->exceptionOnly.uncaught)) { + if ((basket.caught && !pMod->exceptionOnly.caught) || + (!basket.caught && !pMod->exceptionOnly.uncaught)) { return false; } break; case MK_FIELD_ONLY: - if (pMod->fieldOnly.fieldId != basket.fieldId) { - return false; - } - if (!Dbg::MatchType(basket.fieldTypeID, pMod->fieldOnly.refTypeId)) { + if (!Dbg::MatchField(pMod->fieldOnly.refTypeId, pMod->fieldOnly.fieldId, basket.field)) { return false; } break; case MK_STEP: - if (pMod->step.threadId != basket.threadId) { + if (!Dbg::MatchThread(pMod->step.threadId, basket.thread)) { return false; } break; case MK_INSTANCE_ONLY: - if (pMod->instanceOnly.objectId != basket.thisPtr) { + if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr)) { return false; } break; @@ -773,7 +774,7 @@ bool JdwpState::PostVMStart() { } static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_count, - const ModBasket& basket) + ObjectId thread_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { for (size_t i = 0; i < match_count; ++i) { JdwpEvent* pEvent = match_list[i]; @@ -781,11 +782,19 @@ static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_coun << StringPrintf(" (requestId=%#" PRIx32 ")", pEvent->requestId); } std::string thread_name; - JdwpError error = Dbg::GetThreadName(basket.threadId, &thread_name); + JdwpError error = Dbg::GetThreadName(thread_id, &thread_name); if (error != JDWP::ERR_NONE) { thread_name = "<unknown>"; } - VLOG(jdwp) << StringPrintf(" thread=%#" PRIx64, basket.threadId) << " " << thread_name; + VLOG(jdwp) << StringPrintf(" thread=%#" PRIx64, thread_id) << " " << thread_name; +} + +static void SetJdwpLocationFromEventLocation(const JDWP::EventLocation* event_location, + JDWP::JdwpLocation* jdwp_location) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(event_location != nullptr); + DCHECK(jdwp_location != nullptr); + Dbg::SetJdwpLocation(jdwp_location, event_location->method, event_location->dex_pc); } /* @@ -809,14 +818,18 @@ static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_coun * - Single-step to a line with a breakpoint. Should get a single * event message with both events in it. */ -bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, int eventFlags, - const JValue* returnValue) { +bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, + int eventFlags, const JValue* returnValue) { + DCHECK(pLoc != nullptr); + DCHECK(pLoc->method != nullptr); + DCHECK_EQ(pLoc->method->IsStatic(), thisPtr == nullptr); + ModBasket basket; basket.pLoc = pLoc; - basket.classId = pLoc->class_id; + basket.locationClass = pLoc->method->GetDeclaringClass(); basket.thisPtr = thisPtr; - basket.threadId = Dbg::GetThreadSelfId(); - basket.className = Dbg::GetClassName(pLoc->class_id); + basket.thread = Thread::Current(); + basket.className = Dbg::GetClassName(basket.locationClass); /* * On rare occasions we may need to execute interpreted code in the VM @@ -824,7 +837,7 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in * while doing so. (I don't think we currently do this at all, so * this is mostly paranoia.) */ - if (basket.threadId == debug_thread_id_) { + if (basket.thread == GetDebugThread()) { VLOG(jdwp) << "Ignoring location event in JDWP thread"; return false; } @@ -846,29 +859,36 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in size_t match_count = 0; ExpandBuf* pReq = NULL; JdwpSuspendPolicy suspend_policy = SP_NONE; + JdwpEvent** match_list = nullptr; + ObjectId thread_id = 0; { - MutexLock mu(Thread::Current(), event_list_lock_); - JdwpEvent** match_list = AllocMatchList(event_list_size_); - if ((eventFlags & Dbg::kBreakpoint) != 0) { - FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count); - } - if ((eventFlags & Dbg::kSingleStep) != 0) { - FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count); - } - if ((eventFlags & Dbg::kMethodEntry) != 0) { - FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count); - } - if ((eventFlags & Dbg::kMethodExit) != 0) { - FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count); - FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + match_list = AllocMatchList(event_list_size_); + if ((eventFlags & Dbg::kBreakpoint) != 0) { + FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count); + } + if ((eventFlags & Dbg::kSingleStep) != 0) { + FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count); + } + if ((eventFlags & Dbg::kMethodEntry) != 0) { + FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count); + } + if ((eventFlags & Dbg::kMethodExit) != 0) { + FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count); + FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count); + } } if (match_count != 0) { suspend_policy = scanSuspendPolicy(match_list, match_count); + thread_id = Dbg::GetThreadId(basket.thread); + JDWP::JdwpLocation jdwp_location; + SetJdwpLocationFromEventLocation(pLoc, &jdwp_location); + if (VLOG_IS_ON(jdwp)) { - LogMatchingEventsAndThread(match_list, match_count, basket); - VLOG(jdwp) << " location=" << *pLoc; - VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr); + LogMatchingEventsAndThread(match_list, match_count, thread_id); + VLOG(jdwp) << " location=" << jdwp_location; VLOG(jdwp) << " suspend_policy=" << suspend_policy; } @@ -879,79 +899,81 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in for (size_t i = 0; i < match_count; i++) { expandBufAdd1(pReq, match_list[i]->eventKind); expandBufAdd4BE(pReq, match_list[i]->requestId); - expandBufAdd8BE(pReq, basket.threadId); - expandBufAddLocation(pReq, *pLoc); + expandBufAdd8BE(pReq, thread_id); + expandBufAddLocation(pReq, jdwp_location); if (match_list[i]->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) { - Dbg::OutputMethodReturnValue(pLoc->method_id, returnValue, pReq); + Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq); } } } - CleanupMatchList(match_list, match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + CleanupMatchList(match_list, match_count); + } } Dbg::ManageDeoptimization(); - SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id); return match_count != 0; } -bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, FieldId fieldId, - ObjectId thisPtr, const JValue* fieldValue, bool is_modification) { +bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, + mirror::Object* this_object, const JValue* fieldValue, + bool is_modification) { + DCHECK(pLoc != nullptr); + DCHECK(field != nullptr); + DCHECK_EQ(fieldValue != nullptr, is_modification); + DCHECK_EQ(field->IsStatic(), this_object == nullptr); + ModBasket basket; basket.pLoc = pLoc; - basket.classId = pLoc->class_id; - basket.thisPtr = thisPtr; - basket.threadId = Dbg::GetThreadSelfId(); - basket.className = Dbg::GetClassName(pLoc->class_id); - basket.fieldTypeID = typeId; - basket.fieldId = fieldId; - - DCHECK_EQ(fieldValue != nullptr, is_modification); + basket.locationClass = pLoc->method->GetDeclaringClass(); + basket.thisPtr = this_object; + basket.thread = Thread::Current(); + basket.className = Dbg::GetClassName(basket.locationClass); + basket.field = field; if (InvokeInProgress()) { VLOG(jdwp) << "Not posting field event during invoke"; return false; } - // Get field's reference type tag. - JDWP::JdwpTypeTag type_tag; - uint32_t class_status; // unused here. - JdwpError error = Dbg::GetClassInfo(typeId, &type_tag, &class_status, NULL); - if (error != ERR_NONE) { - return false; - } - - // Get instance type tag. - uint8_t tag; - error = Dbg::GetObjectTag(thisPtr, &tag); - if (error != ERR_NONE) { - return false; - } - size_t match_count = 0; ExpandBuf* pReq = NULL; JdwpSuspendPolicy suspend_policy = SP_NONE; + JdwpEvent** match_list = nullptr; + ObjectId thread_id = 0; { - MutexLock mu(Thread::Current(), event_list_lock_); - JdwpEvent** match_list = AllocMatchList(event_list_size_); - - if (is_modification) { - FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count); - } else { - FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + match_list = AllocMatchList(event_list_size_); + if (is_modification) { + FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count); + } else { + FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count); + } } if (match_count != 0) { suspend_policy = scanSuspendPolicy(match_list, match_count); + thread_id = Dbg::GetThreadId(basket.thread); + ObjectRegistry* registry = Dbg::GetObjectRegistry(); + ObjectId instance_id = registry->Add(basket.thisPtr); + RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass()); + FieldId field_id = Dbg::ToFieldId(field); + JDWP::JdwpLocation jdwp_location; + SetJdwpLocationFromEventLocation(pLoc, &jdwp_location); + if (VLOG_IS_ON(jdwp)) { - LogMatchingEventsAndThread(match_list, match_count, basket); - VLOG(jdwp) << " location=" << *pLoc; - VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr); - VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, basket.fieldTypeID) << " " - << Dbg::GetClassName(basket.fieldTypeID); - VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, basket.fieldId) << " " - << Dbg::GetFieldName(basket.fieldId); + LogMatchingEventsAndThread(match_list, match_count, thread_id); + VLOG(jdwp) << " location=" << jdwp_location; + VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, instance_id); + VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, field_type_id) << " " + << Dbg::GetClassName(field_id); + VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, field_id) << " " + << Dbg::GetFieldName(field_id); VLOG(jdwp) << " suspend_policy=" << suspend_policy; } @@ -959,28 +981,41 @@ bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, Field expandBufAdd1(pReq, suspend_policy); expandBufAdd4BE(pReq, match_count); + // Get field's reference type tag. + JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass()); + + // Get instance type tag. + uint8_t tag; + { + ScopedObjectAccessUnchecked soa(Thread::Current()); + tag = Dbg::TagFromObject(soa, basket.thisPtr); + } + for (size_t i = 0; i < match_count; i++) { expandBufAdd1(pReq, match_list[i]->eventKind); expandBufAdd4BE(pReq, match_list[i]->requestId); - expandBufAdd8BE(pReq, basket.threadId); - expandBufAddLocation(pReq, *pLoc); + expandBufAdd8BE(pReq, thread_id); + expandBufAddLocation(pReq, jdwp_location); expandBufAdd1(pReq, type_tag); - expandBufAddRefTypeId(pReq, typeId); - expandBufAddFieldId(pReq, fieldId); + expandBufAddRefTypeId(pReq, field_type_id); + expandBufAddFieldId(pReq, field_id); expandBufAdd1(pReq, tag); - expandBufAddObjectId(pReq, thisPtr); + expandBufAddObjectId(pReq, instance_id); if (is_modification) { - Dbg::OutputFieldValue(fieldId, fieldValue, pReq); + Dbg::OutputFieldValue(field_id, fieldValue, pReq); } } } - CleanupMatchList(match_list, match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + CleanupMatchList(match_list, match_count); + } } Dbg::ManageDeoptimization(); - SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id); return match_count != 0; } @@ -990,8 +1025,8 @@ bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, Field * Valid mods: * Count, ThreadOnly */ -bool JdwpState::PostThreadChange(ObjectId threadId, bool start) { - CHECK_EQ(threadId, Dbg::GetThreadSelfId()); +bool JdwpState::PostThreadChange(Thread* thread, bool start) { + CHECK_EQ(thread, Thread::Current()); /* * I don't think this can happen. @@ -1002,27 +1037,32 @@ bool JdwpState::PostThreadChange(ObjectId threadId, bool start) { } ModBasket basket; - basket.threadId = threadId; + basket.thread = thread; ExpandBuf* pReq = NULL; JdwpSuspendPolicy suspend_policy = SP_NONE; + JdwpEvent** match_list = nullptr; size_t match_count = 0; + ObjectId thread_id = 0; { - // Don't allow the list to be updated while we scan it. - MutexLock mu(Thread::Current(), event_list_lock_); - JdwpEvent** match_list = AllocMatchList(event_list_size_); - - if (start) { - FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count); - } else { - FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count); + { + // Don't allow the list to be updated while we scan it. + MutexLock mu(Thread::Current(), event_list_lock_); + match_list = AllocMatchList(event_list_size_); + if (start) { + FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count); + } else { + FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count); + } } if (match_count != 0) { suspend_policy = scanSuspendPolicy(match_list, match_count); + thread_id = Dbg::GetThreadId(basket.thread); + if (VLOG_IS_ON(jdwp)) { - LogMatchingEventsAndThread(match_list, match_count, basket); + LogMatchingEventsAndThread(match_list, match_count, thread_id); VLOG(jdwp) << " suspend_policy=" << suspend_policy; } @@ -1033,16 +1073,19 @@ bool JdwpState::PostThreadChange(ObjectId threadId, bool start) { for (size_t i = 0; i < match_count; i++) { expandBufAdd1(pReq, match_list[i]->eventKind); expandBufAdd4BE(pReq, match_list[i]->requestId); - expandBufAdd8BE(pReq, basket.threadId); + expandBufAdd8BE(pReq, thread_id); } } - CleanupMatchList(match_list, match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + CleanupMatchList(match_list, match_count); + } } Dbg::ManageDeoptimization(); - SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id); return match_count != 0; } @@ -1076,17 +1119,21 @@ bool JdwpState::PostVMDeath() { * because there's a pretty good chance that we're not going to send it * up the debugger. */ -bool JdwpState::PostException(const JdwpLocation* pThrowLoc, - ObjectId exceptionId, RefTypeId exceptionClassId, - const JdwpLocation* pCatchLoc, ObjectId thisPtr) { - ModBasket basket; +bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object, + const EventLocation* pCatchLoc, mirror::Object* thisPtr) { + DCHECK(exception_object != nullptr); + DCHECK(pThrowLoc != nullptr); + DCHECK(pCatchLoc != nullptr); + DCHECK(pThrowLoc->method != nullptr); + DCHECK_EQ(pThrowLoc->method->IsStatic(), thisPtr == nullptr); + ModBasket basket; basket.pLoc = pThrowLoc; - basket.classId = pThrowLoc->class_id; - basket.threadId = Dbg::GetThreadSelfId(); - basket.className = Dbg::GetClassName(basket.classId); - basket.excepClassId = exceptionClassId; - basket.caught = (pCatchLoc->class_id != 0); + basket.locationClass = pThrowLoc->method->GetDeclaringClass(); + basket.thread = Thread::Current(); + basket.className = Dbg::GetClassName(basket.locationClass); + basket.exceptionClass = exception_object->GetClass(); + basket.caught = (pCatchLoc->method != 0); basket.thisPtr = thisPtr; /* don't try to post an exception caused by the debugger */ @@ -1098,24 +1145,37 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, size_t match_count = 0; ExpandBuf* pReq = NULL; JdwpSuspendPolicy suspend_policy = SP_NONE; + JdwpEvent** match_list = nullptr; + ObjectId thread_id = 0; { - MutexLock mu(Thread::Current(), event_list_lock_); - JdwpEvent** match_list = AllocMatchList(event_list_size_); - FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + match_list = AllocMatchList(event_list_size_); + FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count); + } if (match_count != 0) { suspend_policy = scanSuspendPolicy(match_list, match_count); + thread_id = Dbg::GetThreadId(basket.thread); + ObjectRegistry* registry = Dbg::GetObjectRegistry(); + ObjectId exceptionId = registry->Add(exception_object); + JDWP::JdwpLocation jdwp_throw_location; + JDWP::JdwpLocation jdwp_catch_location; + SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location); + SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location); + if (VLOG_IS_ON(jdwp)) { - LogMatchingEventsAndThread(match_list, match_count, basket); - VLOG(jdwp) << " throwLocation=" << *pThrowLoc; - if (pCatchLoc->class_id == 0) { + std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass())); + + LogMatchingEventsAndThread(match_list, match_count, thread_id); + VLOG(jdwp) << " throwLocation=" << jdwp_throw_location; + if (jdwp_catch_location.class_id == 0) { VLOG(jdwp) << " catchLocation=uncaught"; } else { - VLOG(jdwp) << " catchLocation=" << *pCatchLoc; + VLOG(jdwp) << " catchLocation=" << jdwp_catch_location; } - VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr); - VLOG(jdwp) << StringPrintf(" exceptionClass=%#" PRIx64, basket.excepClassId) << " " - << Dbg::GetClassName(basket.excepClassId); + VLOG(jdwp) << StringPrintf(" exception=%#" PRIx64, exceptionId) << " " + << exceptionClassName; VLOG(jdwp) << " suspend_policy=" << suspend_policy; } @@ -1126,21 +1186,23 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, for (size_t i = 0; i < match_count; i++) { expandBufAdd1(pReq, match_list[i]->eventKind); expandBufAdd4BE(pReq, match_list[i]->requestId); - expandBufAdd8BE(pReq, basket.threadId); - - expandBufAddLocation(pReq, *pThrowLoc); + expandBufAdd8BE(pReq, thread_id); + expandBufAddLocation(pReq, jdwp_throw_location); expandBufAdd1(pReq, JT_OBJECT); expandBufAdd8BE(pReq, exceptionId); - expandBufAddLocation(pReq, *pCatchLoc); + expandBufAddLocation(pReq, jdwp_catch_location); } } - CleanupMatchList(match_list, match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + CleanupMatchList(match_list, match_count); + } } Dbg::ManageDeoptimization(); - SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id); return match_count != 0; } @@ -1151,13 +1213,13 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, * Valid mods: * Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude */ -bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std::string& signature, - int status) { - ModBasket basket; +bool JdwpState::PostClassPrepare(mirror::Class* klass) { + DCHECK(klass != nullptr); - basket.classId = refTypeId; - basket.threadId = Dbg::GetThreadSelfId(); - basket.className = Dbg::GetClassName(basket.classId); + ModBasket basket; + basket.locationClass = klass; + basket.thread = Thread::Current(); + basket.className = Dbg::GetClassName(basket.locationClass); /* suppress class prep caused by debugger */ if (InvokeInProgress()) { @@ -1167,28 +1229,44 @@ bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std ExpandBuf* pReq = NULL; JdwpSuspendPolicy suspend_policy = SP_NONE; + JdwpEvent** match_list = nullptr; size_t match_count = 0; + ObjectId thread_id = 0; { - MutexLock mu(Thread::Current(), event_list_lock_); - JdwpEvent** match_list = AllocMatchList(event_list_size_); - FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count); + { + MutexLock mu(Thread::Current(), event_list_lock_); + match_list = AllocMatchList(event_list_size_); + FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count); + } if (match_count != 0) { suspend_policy = scanSuspendPolicy(match_list, match_count); + thread_id = Dbg::GetThreadId(basket.thread); + ObjectRegistry* registry = Dbg::GetObjectRegistry(); + RefTypeId class_id = registry->AddRefType(basket.locationClass); + + // OLD-TODO - we currently always send both "verified" and "prepared" since + // debuggers seem to like that. There might be some advantage to honesty, + // since the class may not yet be verified. + int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED; + JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass); + std::string temp; + std::string signature(basket.locationClass->GetDescriptor(&temp)); + if (VLOG_IS_ON(jdwp)) { - LogMatchingEventsAndThread(match_list, match_count, basket); - VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, basket.classId)<< " " << signature; + LogMatchingEventsAndThread(match_list, match_count, thread_id); + VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, class_id) << " " << signature; VLOG(jdwp) << " suspend_policy=" << suspend_policy; } - if (basket.threadId == debug_thread_id_) { + if (thread_id == debug_thread_id_) { /* * JDWP says that, for a class prep in the debugger thread, we - * should set threadId to null and if any threads were supposed + * should set thread to null and if any threads were supposed * to be suspended then we suspend all other threads. */ VLOG(jdwp) << " NOTE: class prepare in debugger thread!"; - basket.threadId = 0; + thread_id = 0; if (suspend_policy == SP_EVENT_THREAD) { suspend_policy = SP_ALL; } @@ -1201,20 +1279,23 @@ bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std for (size_t i = 0; i < match_count; i++) { expandBufAdd1(pReq, match_list[i]->eventKind); expandBufAdd4BE(pReq, match_list[i]->requestId); - expandBufAdd8BE(pReq, basket.threadId); - + expandBufAdd8BE(pReq, thread_id); expandBufAdd1(pReq, tag); - expandBufAdd8BE(pReq, refTypeId); + expandBufAdd8BE(pReq, class_id); expandBufAddUtf8String(pReq, signature); expandBufAdd4BE(pReq, status); } } - CleanupMatchList(match_list, match_count); + + { + MutexLock mu(Thread::Current(), event_list_lock_); + CleanupMatchList(match_list, match_count); + } } Dbg::ManageDeoptimization(); - SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id); return match_count != 0; } |