summaryrefslogtreecommitdiffstats
path: root/runtime/debugger.cc
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-04-15 06:43:14 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-04-15 06:43:14 +0000
commitc311d0c85e17773042daaa7a4abc58b3e3c0a0c1 (patch)
tree12103a18b43dd863ab7f3fd51ce9600ef4754d95 /runtime/debugger.cc
parent0a01b38244053e72f33339e733b3ae5e15a5966b (diff)
parent3f52eafe5577b8489f90dc8ed5981b3455206147 (diff)
downloadart-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.cc146
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());