diff options
Diffstat (limited to 'runtime/debugger.cc')
-rw-r--r-- | runtime/debugger.cc | 151 |
1 files changed, 98 insertions, 53 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc index c7f245309f..613e4fe7c7 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -18,6 +18,7 @@ #include <sys/uio.h> +#include <functional> #include <memory> #include <set> #include <vector> @@ -325,6 +326,7 @@ bool Dbg::gDebuggerActive = false; bool Dbg::gDisposed = false; ObjectRegistry* Dbg::gRegistry = nullptr; DebuggerActiveMethodInspectionCallback Dbg::gDebugActiveCallback; +DebuggerDdmCallback Dbg::gDebugDdmCallback; // Deoptimization support. std::vector<DeoptimizationRequest> Dbg::deoptimization_requests_; @@ -342,6 +344,10 @@ uint32_t Dbg::instrumentation_events_ = 0; Dbg::DbgThreadLifecycleCallback Dbg::thread_lifecycle_callback_; Dbg::DbgClassLoadCallback Dbg::class_load_callback_; +void DebuggerDdmCallback::DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { + Dbg::DdmSendChunk(type, data); +} + bool DebuggerActiveMethodInspectionCallback::IsMethodBeingInspected(ArtMethod* m ATTRIBUTE_UNUSED) { return Dbg::IsDebuggerActive(); } @@ -531,6 +537,12 @@ void Dbg::StartJdwp() { CHECK(gRegistry == nullptr); gRegistry = new ObjectRegistry; + { + // Setup the Ddm listener + ScopedObjectAccess soa(Thread::Current()); + Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(&gDebugDdmCallback); + } + // Init JDWP if the debugger is enabled. This may connect out to a // debugger, passively listen for a debugger, or block waiting for a // debugger. @@ -4285,47 +4297,28 @@ void Dbg::FinishInvokeMethod(DebugInvokeReq* pReq) { } } -/* - * "request" contains a full JDWP packet, possibly with multiple chunks. We - * need to process each, accumulate the replies, and ship the whole thing - * back. - * - * Returns "true" if we have a reply. The reply buffer is newly allocated, - * and includes the chunk type/length, followed by the data. - * - * OLD-TODO: we currently assume that the request and reply include a single - * chunk. If this becomes inconvenient we will need to adapt. - */ -bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen) { - Thread* self = Thread::Current(); - JNIEnv* env = self->GetJniEnv(); - - uint32_t type = request->ReadUnsigned32("type"); - uint32_t length = request->ReadUnsigned32("length"); - - // Create a byte[] corresponding to 'request'. - size_t request_length = request->size(); - ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(request_length)); +bool Dbg::DdmHandleChunk(JNIEnv* env, + uint32_t type, + const ArrayRef<const jbyte>& data, + /*out*/uint32_t* out_type, + /*out*/std::vector<uint8_t>* out_data) { + ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(data.size())); if (dataArray.get() == nullptr) { - LOG(WARNING) << "byte[] allocation failed: " << request_length; + LOG(WARNING) << "byte[] allocation failed: " << data.size(); env->ExceptionClear(); return false; } - env->SetByteArrayRegion(dataArray.get(), 0, request_length, - reinterpret_cast<const jbyte*>(request->data())); - request->Skip(request_length); - - // Run through and find all chunks. [Currently just find the first.] - ScopedByteArrayRO contents(env, dataArray.get()); - if (length != request_length) { - LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%zd)", length, request_length); - return false; - } - + env->SetByteArrayRegion(dataArray.get(), + 0, + data.size(), + reinterpret_cast<const jbyte*>(data.data())); // Call "private static Chunk dispatch(int type, byte[] data, int offset, int length)". - ScopedLocalRef<jobject> chunk(env, env->CallStaticObjectMethod(WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer, - WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch, - type, dataArray.get(), 0, length)); + ScopedLocalRef<jobject> chunk( + env, + env->CallStaticObjectMethod( + WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer, + WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch, + type, dataArray.get(), 0, data.size())); if (env->ExceptionCheck()) { LOG(INFO) << StringPrintf("Exception thrown by dispatcher for 0x%08x", type); env->ExceptionDescribe(); @@ -4349,30 +4342,78 @@ bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pRep * * So we're pretty much stuck with copying data around multiple times. */ - ScopedLocalRef<jbyteArray> replyData(env, reinterpret_cast<jbyteArray>(env->GetObjectField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data))); - jint offset = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset); - length = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length); - type = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type); - - VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", type, replyData.get(), offset, length); + ScopedLocalRef<jbyteArray> replyData( + env, + reinterpret_cast<jbyteArray>( + env->GetObjectField( + chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data))); + jint offset = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset); + jint length = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length); + *out_type = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type); + + VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", + type, + replyData.get(), + offset, + length); if (length == 0 || replyData.get() == nullptr) { return false; } - const int kChunkHdrLen = 8; - uint8_t* reply = new uint8_t[length + kChunkHdrLen]; - if (reply == nullptr) { - LOG(WARNING) << "malloc failed: " << (length + kChunkHdrLen); + out_data->resize(length); + env->GetByteArrayRegion(replyData.get(), + offset, + length, + reinterpret_cast<jbyte*>(out_data->data())); + return true; +} + +/* + * "request" contains a full JDWP packet, possibly with multiple chunks. We + * need to process each, accumulate the replies, and ship the whole thing + * back. + * + * Returns "true" if we have a reply. The reply buffer is newly allocated, + * and includes the chunk type/length, followed by the data. + * + * OLD-TODO: we currently assume that the request and reply include a single + * chunk. If this becomes inconvenient we will need to adapt. + */ +bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen) { + Thread* self = Thread::Current(); + JNIEnv* env = self->GetJniEnv(); + + uint32_t type = request->ReadUnsigned32("type"); + uint32_t length = request->ReadUnsigned32("length"); + + // Create a byte[] corresponding to 'request'. + size_t request_length = request->size(); + // Run through and find all chunks. [Currently just find the first.] + if (length != request_length) { + LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%zd)", length, request_length); return false; } - JDWP::Set4BE(reply + 0, type); - JDWP::Set4BE(reply + 4, length); - env->GetByteArrayRegion(replyData.get(), offset, length, reinterpret_cast<jbyte*>(reply + kChunkHdrLen)); - *pReplyBuf = reply; - *pReplyLen = length + kChunkHdrLen; - - VLOG(jdwp) << StringPrintf("dvmHandleDdm returning type=%.4s %p len=%d", reinterpret_cast<char*>(reply), reply, length); + ArrayRef<const jbyte> data(reinterpret_cast<const jbyte*>(request->data()), request_length); + std::vector<uint8_t> out_data; + uint32_t out_type = 0; + request->Skip(request_length); + if (!DdmHandleChunk(env, type, data, &out_type, &out_data)) { + return false; + } + const uint32_t kDdmHeaderSize = 8; + *pReplyLen = out_data.size() + kDdmHeaderSize; + *pReplyBuf = new uint8_t[out_data.size() + kDdmHeaderSize]; + memcpy((*pReplyBuf) + kDdmHeaderSize, out_data.data(), out_data.size()); + JDWP::Set4BE(*pReplyBuf, out_type); + JDWP::Set4BE((*pReplyBuf) + 4, static_cast<uint32_t>(out_data.size())); + VLOG(jdwp) + << StringPrintf("dvmHandleDdm returning type=%.4s", reinterpret_cast<char*>(*pReplyBuf)) + << "0x" << std::hex << reinterpret_cast<uintptr_t>(*pReplyBuf) << std::dec + << " len= " << out_data.size(); return true; } @@ -4482,6 +4523,10 @@ void Dbg::PostThreadDeath(Thread* t) { Dbg::PostThreadStartOrStop(t, CHUNK_TYPE("THDE")); } +void Dbg::DdmSendChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { + DdmSendChunk(type, data.size(), data.data()); +} + void Dbg::DdmSendChunk(uint32_t type, size_t byte_count, const uint8_t* buf) { CHECK(buf != nullptr); iovec vec[1]; |