Include held locks in SIGQUIT thread dumps.

Handy if you have an ANR that's locking related. Quick tour:

   at org.apache.harmony.dalvik.NativeTestTarget.emptyJniStaticSynchronizedMethod0(Native method)
   - locked <0x60135aa8> (a java.lang.Class<org.apache.harmony.dalvik.NativeTestTarget>)
   at java.lang.reflect.Method.invoke(Native method)
   at C.whileTrue(Main.java:63)
   at C.synchronizedOnClassString(Main.java:56)
   - locked <0x60002a70> (a java.lang.Class<java.lang.String>)
   at C.nestedSynchronizationWithTryCatch(Main.java:44)
   - locked <0x61336b90> (a java.lang.String)
   - locked <0x61336bd0> (a java.lang.String)
   at C.nestedSynchronization(Main.java:35)
   - locked <0x61336b18> (a java.lang.String)
   - locked <0x61336b50> (a java.lang.String)
   at C.synchronizedOnClassC(Main.java:30)
   - locked <0x613366f8> (a java.lang.Class<C>)
   at C.noLocks(Main.java:27)
   at C.<clinit>(Main.java:24)
   - locked <0x613366f8> (a java.lang.Class<C>)
   at Main.main(Main.java:19)

A non-static synchronized native method works too:

   at org.apache.harmony.dalvik.NativeTestTarget.emptyJniSynchronizedMethod0(Native method)
   - locked <0x613371a8> (a org.apache.harmony.dalvik.NativeTestTarget)
   ...

Note that most stack traces don't look any different; the above is a
pathological example that exercises different kinds of locking. Testing
with system_server shows most threads don't hold any locks.

Future work (marked by TODO) is that explicit JNI MonitorEnter calls in
native code aren't shown.

Change-Id: I2747f5cddb4ef64b1935736f084a68fe8e4005e9
diff --git a/src/monitor.cc b/src/monitor.cc
index de08b88..e5e867a 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -24,7 +24,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <vector>
+
 #include "class_linker.h"
+#include "dex_instruction.h"
 #include "mutex.h"
 #include "object.h"
 #include "object_utils.h"
@@ -33,6 +36,7 @@
 #include "stl_util.h"
 #include "thread.h"
 #include "thread_list.h"
+#include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -867,11 +871,10 @@
     // We're not waiting on anything.
     return;
   }
-  os << "<" << object << ">";
 
   // - waiting on <0x613f83d8> (a java.lang.ThreadLock) held by thread 5
   // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
-  os << " (a " << PrettyTypeOf(object) << ")";
+  os << "<" << object << "> (a " << PrettyTypeOf(object) << ")";
 
   if (lock_owner != ThreadList::kInvalidId) {
     os << " held by thread " << lock_owner;
@@ -880,6 +883,69 @@
   os << "\n";
 }
 
+static void DumpLockedObject(std::ostream& os, Object* o) {
+  os << "  - locked <" << o << "> (a " << PrettyTypeOf(o) << ")\n";
+}
+
+void Monitor::DescribeLocks(std::ostream& os, StackVisitor* stack_visitor) {
+  Method* m = stack_visitor->GetMethod();
+  CHECK(m != NULL);
+
+  // Native methods are an easy special case.
+  // TODO: use the JNI implementation's table of explicit MonitorEnter calls and dump those too.
+  if (m->IsNative()) {
+    if (m->IsSynchronized()) {
+      Object* jni_this = stack_visitor->GetCurrentSirt()->GetReference(0);
+      DumpLockedObject(os, jni_this);
+    }
+    return;
+  }
+
+  // <clinit> is another special case. The runtime holds the class lock while calling <clinit>.
+  MethodHelper mh(m);
+  if (mh.IsClassInitializer()) {
+    DumpLockedObject(os, m->GetDeclaringClass());
+    // Fall through because there might be synchronization in the user code too.
+  }
+
+  // Is there any reason to believe there's any synchronization in this method?
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  CHECK(code_item != NULL);
+  if (code_item->tries_size_ == 0) {
+    return; // No "tries" implies no synchronization, so no held locks to report.
+  }
+
+  // Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to
+  // the locks held in this stack frame.
+  std::vector<uint32_t> monitor_enter_dex_pcs;
+  verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), monitor_enter_dex_pcs);
+  if (monitor_enter_dex_pcs.empty()) {
+    return;
+  }
+
+  // Verification is an iterative process, so it can visit the same monitor-enter instruction
+  // repeatedly with increasingly accurate type information. Our callers don't want to see
+  // duplicates.
+  STLSortAndRemoveDuplicates(&monitor_enter_dex_pcs);
+
+  for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) {
+    // The verifier works in terms of the dex pcs of the monitor-enter instructions.
+    // We want the registers used by those instructions (so we can read the values out of them).
+    uint32_t dex_pc = monitor_enter_dex_pcs[i];
+    uint16_t monitor_enter_instruction = code_item->insns_[dex_pc];
+
+    // Quick sanity check.
+    if ((monitor_enter_instruction & 0xff) != Instruction::MONITOR_ENTER) {
+      LOG(FATAL) << "expected monitor-enter @" << dex_pc << "; was "
+                 << reinterpret_cast<void*>(monitor_enter_instruction);
+    }
+
+    uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff);
+    Object* o = reinterpret_cast<Object*>(stack_visitor->GetVReg(m, monitor_register));
+    DumpLockedObject(os, o);
+  }
+}
+
 void Monitor::TranslateLocation(const Method* method, uint32_t dex_pc,
                                 const char*& source_file, uint32_t& line_number) const {
   // If method is null, location is unknown