diff options
Diffstat (limited to 'runtime/jdwp')
-rw-r--r-- | runtime/jdwp/jdwp.h | 11 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_event.cc | 99 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_handler.cc | 4 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_main.cc | 51 |
4 files changed, 112 insertions, 53 deletions
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h index 66ebb96..1477324 100644 --- a/runtime/jdwp/jdwp.h +++ b/runtime/jdwp/jdwp.h @@ -197,6 +197,17 @@ struct JdwpState { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* + * A field of interest has been accessed or modified. This is used for field access and field + * modification events. + * + * "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) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + /* * An exception has been thrown. * * Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught. diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index 3b2a6d3..6908047 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -121,26 +121,14 @@ struct ModBasket { /* nothing for StepOnly -- handled differently */ }; -/* - * Dump an event to the log file. - */ -static void dumpEvent(const JdwpEvent* pEvent) { - LOG(INFO) << StringPrintf("Event id=0x%4x %p (prev=%p next=%p):", pEvent->requestId, pEvent, pEvent->prev, pEvent->next); - LOG(INFO) << " kind=" << pEvent->eventKind << " susp=" << pEvent->suspend_policy << " modCount=" << pEvent->modCount; - - for (int i = 0; i < pEvent->modCount; i++) { - const JdwpEventMod* pMod = &pEvent->mods[i]; - LOG(INFO) << " " << pMod->modKind; - /* TODO - show details */ - } -} - static bool NeedsFullDeoptimization(JdwpEventKind eventKind) { switch (eventKind) { case EK_METHOD_ENTRY: case EK_METHOD_EXIT: case EK_METHOD_EXIT_WITH_RETURN_VALUE: case EK_SINGLE_STEP: + case EK_FIELD_ACCESS: + case EK_FIELD_MODIFICATION: return true; default: return false; @@ -177,9 +165,6 @@ JdwpError JdwpState::RegisterEvent(JdwpEvent* pEvent) { if (status != ERR_NONE) { return status; } - } else if (pMod->modKind == MK_FIELD_ONLY) { - /* should be for EK_FIELD_ACCESS or EK_FIELD_MODIFICATION */ - dumpEvent(pEvent); /* TODO - need for field watches */ } } if (NeedsFullDeoptimization(pEvent->eventKind)) { @@ -846,6 +831,86 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in return match_count != 0; } +bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, FieldId fieldId, + ObjectId thisPtr, const JValue* fieldValue, bool is_modification) { + 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.field = fieldId; + + 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; + } + + int match_count = 0; + ExpandBuf* pReq = NULL; + JdwpSuspendPolicy suspend_policy = SP_NONE; + { + 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); + } + if (match_count != 0) { + VLOG(jdwp) << "EVENT: " << match_list[0]->eventKind << "(" << match_count << " total) " + << basket.className << "." << Dbg::GetMethodName(pLoc->method_id) + << StringPrintf(" thread=%#" PRIx64 " dex_pc=%#" PRIx64 ")", + basket.threadId, pLoc->dex_pc); + + suspend_policy = scanSuspendPolicy(match_list, match_count); + VLOG(jdwp) << " suspend_policy=" << suspend_policy; + + pReq = eventPrep(); + expandBufAdd1(pReq, suspend_policy); + expandBufAdd4BE(pReq, match_count); + + for (int 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); + expandBufAdd1(pReq, type_tag); + expandBufAddRefTypeId(pReq, typeId); + expandBufAddFieldId(pReq, fieldId); + expandBufAdd1(pReq, tag); + expandBufAddObjectId(pReq, thisPtr); + if (is_modification) { + Dbg::OutputFieldValue(fieldId, fieldValue, pReq); + } + } + } + + CleanupMatchList(match_list, match_count); + } + + Dbg::ManageDeoptimization(); + + SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId); + return match_count != 0; +} + /* * A thread is starting or stopping. * diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index c2a2b54..8f224d2 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -353,8 +353,8 @@ static JdwpError VM_DisposeObjects(JdwpState*, Request& request, ExpandBuf*) static JdwpError VM_Capabilities(JdwpState*, Request&, ExpandBuf* reply) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - expandBufAdd1(reply, false); // canWatchFieldModification - expandBufAdd1(reply, false); // canWatchFieldAccess + expandBufAdd1(reply, true); // canWatchFieldModification + expandBufAdd1(reply, true); // canWatchFieldAccess expandBufAdd1(reply, true); // canGetBytecodes expandBufAdd1(reply, true); // canGetSyntheticAttribute expandBufAdd1(reply, true); // canGetOwnedMonitorInfo diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc index 5fc0228..8e22c1d 100644 --- a/runtime/jdwp/jdwp_main.cc +++ b/runtime/jdwp/jdwp_main.cc @@ -237,55 +237,41 @@ JdwpState* JdwpState::Create(const JdwpOptions* options) { Locks::mutator_lock_->AssertNotHeld(self); UniquePtr<JdwpState> state(new JdwpState(options)); switch (options->transport) { - case kJdwpTransportSocket: - InitSocketTransport(state.get(), options); - break; + case kJdwpTransportSocket: + InitSocketTransport(state.get(), options); + break; #ifdef HAVE_ANDROID_OS - case kJdwpTransportAndroidAdb: - InitAdbTransport(state.get(), options); - break; + case kJdwpTransportAndroidAdb: + InitAdbTransport(state.get(), options); + break; #endif - default: - LOG(FATAL) << "Unknown transport: " << options->transport; + default: + LOG(FATAL) << "Unknown transport: " << options->transport; } - if (!options->suspend) { + { /* * Grab a mutex before starting the thread. This ensures they * won't signal the cond var before we're waiting. */ MutexLock thread_start_locker(self, state->thread_start_lock_); + /* * We have bound to a port, or are trying to connect outbound to a * debugger. Create the JDWP thread and let it continue the mission. */ - CHECK_PTHREAD_CALL(pthread_create, (&state->pthread_, NULL, StartJdwpThread, state.get()), "JDWP thread"); + CHECK_PTHREAD_CALL(pthread_create, (&state->pthread_, nullptr, StartJdwpThread, state.get()), + "JDWP thread"); /* * Wait until the thread finishes basic initialization. - * TODO: cond vars should be waited upon in a loop */ - state->thread_start_cond_.Wait(self); - } else { - { - /* - * Grab a mutex before starting the thread. This ensures they - * won't signal the cond var before we're waiting. - */ - MutexLock thread_start_locker(self, state->thread_start_lock_); - /* - * We have bound to a port, or are trying to connect outbound to a - * debugger. Create the JDWP thread and let it continue the mission. - */ - CHECK_PTHREAD_CALL(pthread_create, (&state->pthread_, NULL, StartJdwpThread, state.get()), "JDWP thread"); - - /* - * Wait until the thread finishes basic initialization. - * TODO: cond vars should be waited upon in a loop - */ + while (!state->debug_thread_started_) { state->thread_start_cond_.Wait(self); } + } + if (options->suspend) { /* * For suspend=y, wait for the debugger to connect to us or for us to * connect to the debugger. @@ -481,11 +467,8 @@ void JdwpState::Run() { /* process requests until the debugger drops */ bool first = true; while (!Dbg::IsDisposed()) { - { - // sanity check -- shouldn't happen? - MutexLock mu(thread_, *Locks::thread_suspend_count_lock_); - CHECK_EQ(thread_->GetState(), kWaitingInMainDebuggerLoop); - } + // sanity check -- shouldn't happen? + CHECK_EQ(thread_->GetState(), kWaitingInMainDebuggerLoop); if (!netState->ProcessIncoming()) { /* blocking read */ |