JDWP: fix breakpoint on catch statement

Setting a breakpoint on a catch statement in the source actually
installs the breakpoint on a DEX move-exception instruction. At this
point, an exception is pending in the current thread.

The issue is no exception must be pending in the current thread to
report the breakpoint event. This is required to be able to call JNI
functions to create JDWP ids.

This CL fixes it by clearing the pending exception before reporting
event and restore it after reporting the event.

Bug: 21382373
Change-Id: Id3c60cca398135a3e0859a1ccb645b9c99d5ca76
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 0eb7f2b..ef1aa6a 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2806,7 +2806,27 @@
   JDWP::EventLocation location;
   SetEventLocation(&location, m, dex_pc);
 
+  // We need to be sure no exception is pending when calling JdwpState::PostLocationEvent.
+  // This is required to be able to call JNI functions to create JDWP ids. To achieve this,
+  // we temporarily clear the current thread's exception (if any) and will restore it after
+  // the call.
+  // Note: the only way to get a pending exception here is to suspend on a move-exception
+  // instruction.
+  Thread* const self = Thread::Current();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Throwable> pending_exception(hs.NewHandle(self->GetException()));
+  self->ClearException();
+  if (kIsDebugBuild && pending_exception.Get() != nullptr) {
+    const DexFile::CodeItem* code_item = location.method->GetCodeItem();
+    const Instruction* instr = Instruction::At(&code_item->insns_[location.dex_pc]);
+    CHECK_EQ(Instruction::MOVE_EXCEPTION, instr->Opcode());
+  }
+
   gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value);
+
+  if (pending_exception.Get() != nullptr) {
+    self->SetException(pending_exception.Get());
+  }
 }
 
 void Dbg::PostFieldAccessEvent(mirror::ArtMethod* m, int dex_pc,