diff options
author | Sebastien Hertz <shertz@google.com> | 2014-04-15 06:43:14 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-04-15 06:43:14 +0000 |
commit | c311d0c85e17773042daaa7a4abc58b3e3c0a0c1 (patch) | |
tree | 12103a18b43dd863ab7f3fd51ce9600ef4754d95 /runtime/debugger.cc | |
parent | 0a01b38244053e72f33339e733b3ae5e15a5966b (diff) | |
parent | 3f52eafe5577b8489f90dc8ed5981b3455206147 (diff) | |
download | art-c311d0c85e17773042daaa7a4abc58b3e3c0a0c1.zip art-c311d0c85e17773042daaa7a4abc58b3e3c0a0c1.tar.gz art-c311d0c85e17773042daaa7a4abc58b3e3c0a0c1.tar.bz2 |
Merge "Prepare field watchpoint support"
Diffstat (limited to 'runtime/debugger.cc')
-rw-r--r-- | runtime/debugger.cc | 146 |
1 files changed, 108 insertions, 38 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc index bcecbc2..c52a588 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -126,14 +126,14 @@ static std::ostream& operator<<(std::ostream& os, const Breakpoint& rhs) return os; } -class DebugInstrumentationListener : public instrumentation::InstrumentationListener { +class DebugInstrumentationListener FINAL : public instrumentation::InstrumentationListener { public: DebugInstrumentationListener() {} virtual ~DebugInstrumentationListener() {} - virtual void MethodEntered(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void MethodEntered(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t dex_pc) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (method->IsNative()) { // TODO: post location events is a suspension point and native method entry stubs aren't. return; @@ -141,10 +141,9 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList Dbg::PostLocationEvent(method, 0, this_object, Dbg::kMethodEntry, nullptr); } - virtual void MethodExited(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, - uint32_t dex_pc, const JValue& return_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void MethodExited(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t dex_pc, const JValue& return_value) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (method->IsNative()) { // TODO: post location events is a suspension point and native method entry stubs aren't. return; @@ -152,26 +151,41 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList Dbg::PostLocationEvent(method, dex_pc, this_object, Dbg::kMethodExit, &return_value); } - virtual void MethodUnwind(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void MethodUnwind(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t dex_pc) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // We're not recorded to listen to this kind of event, so complain. LOG(ERROR) << "Unexpected method unwind event in debugger " << PrettyMethod(method) << " " << dex_pc; } - virtual void DexPcMoved(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t new_dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void DexPcMoved(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t new_dex_pc) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Dbg::UpdateDebugger(thread, this_object, method, new_dex_pc); } - virtual void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location, - mirror::ArtMethod* catch_method, uint32_t catch_dex_pc, - mirror::Throwable* exception_object) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Dbg::PostException(thread, throw_location, catch_method, catch_dex_pc, exception_object); + void FieldRead(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t dex_pc, mirror::ArtField* field) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Dbg::PostFieldAccessEvent(method, dex_pc, this_object, field); + } + + void FieldWritten(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method, + uint32_t dex_pc, mirror::ArtField* field, const JValue& field_value) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Dbg::PostFieldModificationEvent(method, dex_pc, this_object, field, &field_value); + } + + void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location, + mirror::ArtMethod* catch_method, uint32_t catch_dex_pc, + mirror::Throwable* exception_object) + OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Dbg::PostException(throw_location, catch_method, catch_dex_pc, exception_object); } + + private: + DISALLOW_COPY_AND_ASSIGN(DebugInstrumentationListener); } gDebugInstrumentationListener; // JDWP is allowed unless the Zygote forbids it. @@ -625,6 +639,14 @@ bool Dbg::IsDisposed() { return gDisposed; } +// All the instrumentation events the debugger is registered for. +static constexpr uint32_t kListenerEvents = instrumentation::Instrumentation::kMethodEntered | + instrumentation::Instrumentation::kMethodExited | + instrumentation::Instrumentation::kDexPcMoved | + instrumentation::Instrumentation::kFieldRead | + instrumentation::Instrumentation::kFieldWritten | + instrumentation::Instrumentation::kExceptionCaught; + void Dbg::GoActive() { // Enable all debugging features, including scans for breakpoints. // This is a no-op if we're already active. @@ -651,11 +673,7 @@ void Dbg::GoActive() { ThreadState old_state = self->SetStateUnsafe(kRunnable); CHECK_NE(old_state, kRunnable); runtime->GetInstrumentation()->EnableDeoptimization(); - runtime->GetInstrumentation()->AddListener(&gDebugInstrumentationListener, - instrumentation::Instrumentation::kMethodEntered | - instrumentation::Instrumentation::kMethodExited | - instrumentation::Instrumentation::kDexPcMoved | - instrumentation::Instrumentation::kExceptionCaught); + runtime->GetInstrumentation()->AddListener(&gDebugInstrumentationListener, kListenerEvents); gDebuggerActive = true; CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable); runtime->GetThreadList()->ResumeAll(); @@ -686,11 +704,7 @@ void Dbg::Disconnected() { deoptimization_requests_.clear(); full_deoptimization_event_count_ = 0U; } - runtime->GetInstrumentation()->RemoveListener(&gDebugInstrumentationListener, - instrumentation::Instrumentation::kMethodEntered | - instrumentation::Instrumentation::kMethodExited | - instrumentation::Instrumentation::kDexPcMoved | - instrumentation::Instrumentation::kExceptionCaught); + runtime->GetInstrumentation()->RemoveListener(&gDebugInstrumentationListener, kListenerEvents); runtime->GetInstrumentation()->DisableDeoptimization(); gDebuggerActive = false; } @@ -1590,6 +1604,13 @@ void Dbg::OutputMethodReturnValue(JDWP::MethodId method_id, const JValue* return OutputJValue(tag, return_value, pReply); } +void Dbg::OutputFieldValue(JDWP::FieldId field_id, const JValue* field_value, + JDWP::ExpandBuf* pReply) { + mirror::ArtField* f = FromFieldId(field_id); + JDWP::JdwpTag tag = BasicTagFromDescriptor(FieldHelper(f).GetTypeDescriptor()); + OutputJValue(tag, field_value, pReply); +} + JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id, std::vector<uint8_t>& bytecodes) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -2462,21 +2483,70 @@ JDWP::JdwpError Dbg::SetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame return visitor.error_; } +JDWP::ObjectId Dbg::GetThisObjectIdForEvent(mirror::Object* this_object) { + // If 'this_object' isn't already in the registry, we know that we're not looking for it, so + // there's no point adding it to the registry and burning through ids. + // When registering an event request with an instance filter, we've been given an existing object + // id so it must already be present in the registry when the event fires. + JDWP::ObjectId this_id = 0; + if (this_object != nullptr && gRegistry->Contains(this_object)) { + this_id = gRegistry->Add(this_object); + } + return this_id; +} + void Dbg::PostLocationEvent(mirror::ArtMethod* m, int dex_pc, mirror::Object* this_object, int event_flags, const JValue* return_value) { + if (!IsDebuggerActive()) { + return; + } + DCHECK(m != nullptr); + DCHECK_EQ(m->IsStatic(), this_object == nullptr); JDWP::JdwpLocation location; SetLocation(location, m, dex_pc); - // If 'this_object' isn't already in the registry, we know that we're not looking for it, - // so there's no point adding it to the registry and burning through ids. - JDWP::ObjectId this_id = 0; - if (gRegistry->Contains(this_object)) { - this_id = gRegistry->Add(this_object); - } + // We need 'this' for InstanceOnly filters only. + JDWP::ObjectId this_id = GetThisObjectIdForEvent(this_object); gJdwpState->PostLocationEvent(&location, this_id, event_flags, return_value); } -void Dbg::PostException(Thread* thread, const ThrowLocation& throw_location, +void Dbg::PostFieldAccessEvent(mirror::ArtMethod* m, int dex_pc, + mirror::Object* this_object, mirror::ArtField* f) { + if (!IsDebuggerActive()) { + return; + } + DCHECK(m != nullptr); + DCHECK(f != nullptr); + JDWP::JdwpLocation location; + SetLocation(location, m, dex_pc); + + JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass()); + JDWP::FieldId field_id = ToFieldId(f); + JDWP::ObjectId this_id = gRegistry->Add(this_object); + + gJdwpState->PostFieldEvent(&location, type_id, field_id, this_id, nullptr, false); +} + +void Dbg::PostFieldModificationEvent(mirror::ArtMethod* m, int dex_pc, + mirror::Object* this_object, mirror::ArtField* f, + const JValue* field_value) { + if (!IsDebuggerActive()) { + return; + } + DCHECK(m != nullptr); + DCHECK(f != nullptr); + DCHECK(field_value != nullptr); + JDWP::JdwpLocation location; + SetLocation(location, m, dex_pc); + + JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass()); + JDWP::FieldId field_id = ToFieldId(f); + JDWP::ObjectId this_id = gRegistry->Add(this_object); + + gJdwpState->PostFieldEvent(&location, type_id, field_id, this_id, field_value, true); +} + +void Dbg::PostException(const ThrowLocation& throw_location, mirror::ArtMethod* catch_method, uint32_t catch_dex_pc, mirror::Throwable* exception_object) { if (!IsDebuggerActive()) { @@ -2488,8 +2558,8 @@ void Dbg::PostException(Thread* thread, const ThrowLocation& throw_location, JDWP::JdwpLocation catch_location; SetLocation(catch_location, catch_method, catch_dex_pc); - // We need 'this' for InstanceOnly filters. - JDWP::ObjectId this_id = gRegistry->Add(throw_location.GetThis()); + // We need 'this' for InstanceOnly filters only. + JDWP::ObjectId this_id = GetThisObjectIdForEvent(throw_location.GetThis()); JDWP::ObjectId exception_id = gRegistry->Add(exception_object); JDWP::RefTypeId exception_class_id = gRegistry->AddRefType(exception_object->GetClass()); |